diff --git a/rostests/winetests/directory.rbuild b/rostests/winetests/directory.rbuild index 27255cafcd7..7f852f45a04 100644 --- a/rostests/winetests/directory.rbuild +++ b/rostests/winetests/directory.rbuild @@ -55,15 +55,30 @@ + + + + + + + + + + + + + + + diff --git a/rostests/winetests/inetcomm/inetcomm.rbuild b/rostests/winetests/inetcomm/inetcomm.rbuild new file mode 100644 index 00000000000..9f2b9eb6a83 --- /dev/null +++ b/rostests/winetests/inetcomm/inetcomm.rbuild @@ -0,0 +1,13 @@ + + -Wno-format + . + mimeintl.c + mimeole.c + testlist.c + wine + inetcomm + oleaut32 + ole32 + kernel32 + 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..9e13b26521e --- /dev/null +++ b/rostests/winetests/inetmib1/inetmib1.rbuild @@ -0,0 +1,10 @@ + + -Wno-format + . + main.c + testlist.c + wine + snmpapi + kernel32 + ntdll + diff --git a/rostests/winetests/inetmib1/main.c b/rostests/winetests/inetmib1/main.c new file mode 100644 index 00000000000..13613fd9d42 --- /dev/null +++ b/rostests/winetests/inetmib1/main.c @@ -0,0 +1,476 @@ +/* + * 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) + { + 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) + { + 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(); +} 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/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..5a95a1dd54d --- /dev/null +++ b/rostests/winetests/itss/itss.rbuild @@ -0,0 +1,11 @@ + + -Wno-format + . + protocol.c + rsrc.rc + testlist.c + wine + ole32 + kernel32 + 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/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..64e056ece75 --- /dev/null +++ b/rostests/winetests/localspl/localspl.rbuild @@ -0,0 +1,10 @@ + + -Wno-format + . + localmon.c + testlist.c + wine + kernel32 + 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..b7ae0bd9957 --- /dev/null +++ b/rostests/winetests/localui/localui.rbuild @@ -0,0 +1,10 @@ + + -Wno-format + . + localui.c + testlist.c + wine + kernel32 + 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 } +};