[PATCH v2 1/7] activeds: implement ADsSetLastError() and ADsGetLastError()
Damjan Jovanovic
damjan.jov at gmail.com
Sat Feb 13 04:43:26 CST 2021
Signed-off-by: Damjan Jovanovic <damjan.jov at gmail.com>
---
dlls/activeds/activeds_main.c | 90 ++++++++++++++++++++++++++++++++--
dlls/activeds/tests/activeds.c | 69 ++++++++++++++++++++++++++
include/adshlp.h | 2 +
3 files changed, 157 insertions(+), 4 deletions(-)
-------------- next part --------------
diff --git a/dlls/activeds/activeds_main.c b/dlls/activeds/activeds_main.c
index 1b22da67653..75dd312c729 100644
--- a/dlls/activeds/activeds_main.c
+++ b/dlls/activeds/activeds_main.c
@@ -40,11 +40,21 @@
WINE_DEFAULT_DEBUG_CHANNEL(activeds);
+static DWORD tls_idx;
+
+struct activeds_tls_data {
+ DWORD last_err;
+ WCHAR *last_error;
+ WCHAR *last_provider;
+};
+
/*****************************************************
* DllMain
*/
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
+ struct activeds_tls_data *tls;
+
TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);
switch(fdwReason)
@@ -53,6 +63,16 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
return FALSE; /* prefer native version */
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls( hinstDLL );
+ tls_idx = TlsAlloc();
+ break;
+ case DLL_PROCESS_DETACH:
+ tls = TlsGetValue(tls_idx);
+ if (tls != NULL)
+ {
+ HeapFree(GetProcessHeap(), 0, tls->last_error);
+ HeapFree(GetProcessHeap(), 0, tls->last_provider);
+ HeapFree(GetProcessHeap(), 0, tls);
+ }
break;
}
return TRUE;
@@ -232,9 +252,39 @@ HRESULT WINAPI ADsOpenObject(LPCWSTR path, LPCWSTR user, LPCWSTR password, DWORD
/*****************************************************
* ADsSetLastError [ACTIVEDS.12]
*/
-VOID WINAPI ADsSetLastError(DWORD dwErr, LPWSTR pszError, LPWSTR pszProvider)
+VOID WINAPI ADsSetLastError(DWORD dwErr, LPCWSTR pszError, LPCWSTR pszProvider)
{
- FIXME("(%d,%p,%p)!stub\n", dwErr, pszError, pszProvider);
+ struct activeds_tls_data *tls;
+
+ TRACE("(%d,%s,%s)\n", dwErr, debugstr_w(pszError), debugstr_w(pszProvider));
+
+ tls = TlsGetValue(tls_idx);
+ if (tls == NULL)
+ {
+ tls = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*tls));
+ if (tls == NULL)
+ return;
+ TlsSetValue(tls_idx, tls);
+ }
+ tls->last_err = dwErr;
+
+ HeapFree(GetProcessHeap(), 0, tls->last_error);
+ tls->last_error = NULL;
+ if (pszError == NULL)
+ pszError = L"";
+ tls->last_error = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pszError)+1) * sizeof(WCHAR));
+ if (tls->last_error == NULL)
+ return;
+ lstrcpyW(tls->last_error, pszError);
+
+ HeapFree(GetProcessHeap(), 0, tls->last_provider);
+ tls->last_provider = NULL;
+ if (pszProvider == NULL)
+ pszProvider = L"";
+ tls->last_provider = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pszProvider)+1) * sizeof(WCHAR));
+ if (tls->last_provider == NULL)
+ return;
+ lstrcpyW(tls->last_provider, pszProvider);
}
/*****************************************************
@@ -242,8 +292,40 @@ VOID WINAPI ADsSetLastError(DWORD dwErr, LPWSTR pszError, LPWSTR pszProvider)
*/
HRESULT WINAPI ADsGetLastError(LPDWORD perror, LPWSTR errorbuf, DWORD errorbuflen, LPWSTR namebuf, DWORD namebuflen)
{
- FIXME("(%p,%p,%d,%p,%d)!stub\n", perror, errorbuf, errorbuflen, namebuf, namebuflen);
- return E_NOTIMPL;
+ struct activeds_tls_data *tls;
+ LPCWSTR last_error;
+ LPCWSTR last_provider;
+
+ TRACE("(%p,%p,%d,%p,%d)\n", perror, errorbuf, errorbuflen, namebuf, namebuflen);
+
+ if (errorbuf == NULL || namebuf == NULL)
+ return E_POINTER;
+ tls = TlsGetValue(tls_idx);
+ if (tls == NULL)
+ {
+ if (GetLastError() == 0)
+ {
+ *perror = NO_ERROR;
+ if (errorbuflen > 0) errorbuf[0] = 0;
+ if (namebuflen > 0) namebuf[0] = 0;
+ return S_OK;
+ }
+ else
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ last_error = tls->last_error;
+ if (last_error == NULL)
+ last_error = L"";
+ last_provider = tls->last_provider;
+ if (last_provider == NULL)
+ last_provider = L"";
+ *perror = tls->last_err;
+ wcsncpy(errorbuf, last_error, errorbuflen);
+ if (errorbuflen > 0) errorbuf[errorbuflen - 1] = 0;
+ wcsncpy(namebuf, last_provider, namebuflen);
+ if (namebuflen > 0) namebuf[namebuflen - 1] = 0;
+ return S_OK;
}
/*****************************************************
diff --git a/dlls/activeds/tests/activeds.c b/dlls/activeds/tests/activeds.c
index c2dc3d58c4b..c542faea8a0 100644
--- a/dlls/activeds/tests/activeds.c
+++ b/dlls/activeds/tests/activeds.c
@@ -161,12 +161,81 @@ static void test_Pathname(void)
IADsPathname_Release(path);
}
+#define EXPECT_LAST_ERR(err,error,provider) _expect_last_err(err, error, provider, __LINE__)
+static void _expect_last_err(DWORD err, const WCHAR *error, const WCHAR *provider, int line)
+{
+ HRESULT hr;
+ DWORD last_err;
+ WCHAR last_error[MAX_PATH];
+ WCHAR last_provider[MAX_PATH];
+
+ hr = ADsGetLastError(&last_err, last_error, MAX_PATH, last_provider, MAX_PATH);
+ ok_(__FILE__,line)(SUCCEEDED(hr), "ADsGetLastError() failed with 0x%08x\n", hr);
+ ok_(__FILE__,line)(last_err == err, "unexpected last err %d\n", last_err);
+ ok_(__FILE__,line)(!lstrcmpW(last_error, error), "unexpected last error %s\n", wine_dbgstr_w(last_error));
+ ok_(__FILE__,line)(!lstrcmpW(last_provider, provider), "unexpected last provider %s\n", wine_dbgstr_w(last_provider));
+}
+
+static void test_LastError(void)
+{
+ HRESULT hr;
+ DWORD last_err;
+ WCHAR last_error[MAX_PATH];
+ WCHAR last_provider[MAX_PATH];
+ WCHAR *large_str;
+
+ ADsSetLastError(NO_ERROR, NULL, NULL);
+ EXPECT_LAST_ERR(NO_ERROR, L"", L"");
+
+ ADsSetLastError(ERROR_OUTOFMEMORY, NULL, NULL);
+ EXPECT_LAST_ERR(ERROR_OUTOFMEMORY, L"", L"");
+
+ ADsSetLastError(HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY), NULL, NULL);
+ EXPECT_LAST_ERR(HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY), L"", L"");
+
+ /* SetLastError() and ADsSetLastError() do not affect each other */
+ SetLastError(NO_ERROR);
+ ADsSetLastError(ERROR_OUTOFMEMORY, NULL, NULL);
+ ok(GetLastError() == NO_ERROR, "unexpected GetLastError() = %d\n", GetLastError());
+ EXPECT_LAST_ERR(ERROR_OUTOFMEMORY, L"", L"");
+ SetLastError(ERROR_INVALID_HANDLE);
+ EXPECT_LAST_ERR(ERROR_OUTOFMEMORY, L"", L"");
+
+ /* The error/provider buffers are mandatory, even when they were previously set to NULL... */
+ ADsSetLastError(ERROR_OUTOFMEMORY, NULL, NULL);
+ hr = ADsGetLastError(&last_err, last_error, MAX_PATH, NULL, 0);
+ ok(hr == E_POINTER, "unexpected hr 0x%08x\n", hr);
+ hr = ADsGetLastError(&last_err, NULL, 0, last_provider, MAX_PATH);
+ ok(hr == E_POINTER, "unexpected hr 0x%08x\n", hr);
+
+ /* ... but non-NULL buffers with short sizes are silently trimmed. */
+ ADsSetLastError(ERROR_OUTOFMEMORY, L"no mem", L"wine");
+ hr = ADsGetLastError(&last_err, last_error, 0, last_provider, 0);
+ ok(hr == S_OK, "unexpected hr 0x%08x\n", hr);
+ hr = ADsGetLastError(&last_err, last_error, 3, last_provider, 2);
+ ok(hr == S_OK, "unexpected hr 0x%08x\n", hr);
+ ok(!lstrcmpW(last_error, L"no"), "unexpected value %s\n", wine_dbgstr_w(last_error));
+ ok(!lstrcmpW(last_provider, L"w"), "unexpected value %s\n", wine_dbgstr_w(last_provider));
+
+ /* Does not internally trim long strings */
+ large_str = HeapAlloc(GetProcessHeap(), 0, 0x10000 * sizeof(WCHAR));
+ ok(large_str != NULL, "no memory\n");
+ memset(large_str, 'a', 0x10000 * sizeof(WCHAR));
+ large_str[0x10000 - 1] = 0;
+ ADsSetLastError(NO_ERROR, NULL, large_str);
+ hr = ADsGetLastError(&last_err, last_error, MAX_PATH, large_str, 0x10000);
+ ok(SUCCEEDED(hr), "ADsGetLastError() failed with 0x%08x\n", hr);
+ ok(lstrlenW(large_str) == 0x10000 - 1, "string length %d\n", lstrlenW(large_str));
+ HeapFree(GetProcessHeap(), 0, large_str);
+}
+
START_TEST(activeds)
{
CoInitialize(NULL);
test_Pathname();
test_ADsBuildVarArrayStr();
+ test_LastError();
CoUninitialize();
}
diff --git a/include/adshlp.h b/include/adshlp.h
index dac57857edb..5233fc50f66 100644
--- a/include/adshlp.h
+++ b/include/adshlp.h
@@ -27,7 +27,9 @@ HRESULT WINAPI ADsBuildEnumerator(IADsContainer*,IEnumVARIANT**);
HRESULT WINAPI ADsBuildVarArrayStr(LPWSTR*,DWORD,VARIANT*);
HRESULT WINAPI ADsEnumerateNext(IEnumVARIANT*,ULONG,VARIANT*,ULONG*);
HRESULT WINAPI ADsGetObject(LPCWSTR,REFIID,VOID**);
+HRESULT WINAPI ADsGetLastError(LPDWORD lpError, LPWSTR lpErrorBuf, DWORD dwErrorBufLen, LPWSTR lpNameBuf, DWORD dwNameBufLen);
HRESULT WINAPI ADsOpenObject(LPCWSTR,LPCWSTR,LPCWSTR,DWORD,REFIID,VOID**);
+VOID WINAPI ADsSetLastError(DWORD dwErr, LPCWSTR pszError, LPCWSTR pszProvider);
LPWSTR WINAPI AllocADsStr(LPWSTR);
BOOL WINAPI FreeADsMem(LPVOID);
BOOL WINAPI FreeADsStr(LPWSTR);
More information about the wine-devel
mailing list