wintrust: Implementation of WintrustAddActionID.
diff --git a/dlls/wintrust/register.c b/dlls/wintrust/register.c
index 93b1fed..10ccbae 100644
--- a/dlls/wintrust/register.c
+++ b/dlls/wintrust/register.c
@@ -49,6 +49,48 @@
 static const WCHAR DiagnosticPolicy[] = {'D','i','a','g','n','o','s','t','i','c','P','o','l','i','c','y','\\', 0};
 static const WCHAR Cleanup[]          = {'C','l','e','a','n','u','p','\\', 0};
 
+/***********************************************************************
+ *              WINTRUST_WriteProviderToReg
+ *
+ * Helper function for WintrustAddActionID
+ *
+ */
+static LONG WINTRUST_WriteProviderToReg(WCHAR* GuidString,
+                                        const WCHAR* FunctionType,
+                                        CRYPT_TRUST_REG_ENTRY RegEntry)
+{
+    static const WCHAR Dll[]      = {'$','D','L','L', 0};
+    static const WCHAR Function[] = {'$','F','u','n','c','t','i','o','n', 0};
+    WCHAR ProvKey[MAX_PATH];
+    HKEY Key;
+    LONG Res = ERROR_SUCCESS;
+
+    /* Create the needed key string */
+    ProvKey[0]='\0';
+    lstrcatW(ProvKey, Trust);
+    lstrcatW(ProvKey, FunctionType);
+    lstrcatW(ProvKey, GuidString);
+
+    if (!RegEntry.pwszDLLName || !RegEntry.pwszFunctionName)
+        return ERROR_INVALID_PARAMETER;
+
+    Res = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ProvKey, 0, NULL, 0, KEY_WRITE, NULL, &Key, NULL);
+    if (Res != ERROR_SUCCESS) goto error_close_key;
+
+    /* Create the $DLL entry */
+    Res = RegSetValueExW(Key, Dll, 0, REG_SZ, (BYTE*)RegEntry.pwszDLLName,
+        (lstrlenW(RegEntry.pwszDLLName) + 1)*sizeof(WCHAR));
+    if (Res != ERROR_SUCCESS) goto error_close_key;
+
+    /* Create the $Function entry */
+    Res = RegSetValueExW(Key, Function, 0, REG_SZ, (BYTE*)RegEntry.pwszFunctionName,
+        (lstrlenW(RegEntry.pwszFunctionName) + 1)*sizeof(WCHAR));
+
+error_close_key:
+    RegCloseKey(Key);
+
+    return Res;
+}
 
 /***********************************************************************
  *		WintrustAddActionID (WINTRUST.@)
@@ -71,17 +113,77 @@
  *   to the registry. No verification takes place whether a DLL or it's
  *   entrypoints exist.
  *   Information in the registry will always be overwritten.
+ *
  */
 BOOL WINAPI WintrustAddActionID( GUID* pgActionID, DWORD fdwFlags,
                                  CRYPT_REGISTER_ACTIONID* psProvInfo)
 {
-    FIXME("%p %lx %p\n", pgActionID, fdwFlags, psProvInfo);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    static const WCHAR wszFormat[] = {'{','%','0','8','l','X','-','%','0','4','X','-','%','0','4','X','-',
+                                      '%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2',
+                                      'X','%','0','2','X','%','0','2','X','}', 0};
+
+    WCHAR GuidString[39];
+    LONG Res;
+    LONG WriteActionError = ERROR_SUCCESS;
+
+    TRACE("%p %lx %p\n", debugstr_guid(pgActionID), fdwFlags, psProvInfo);
+
+    /* Some sanity checks.
+     * We use the W2K3 last error as it makes more sense (W2K leaves the last error
+     * as is).
+     */
+    if (!pgActionID ||
+        !psProvInfo ||
+        (psProvInfo->cbStruct != sizeof(CRYPT_REGISTER_ACTIONID)))
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    /* Create this string only once, instead of in the helper function */
+    wsprintfW(GuidString, wszFormat, pgActionID->Data1, pgActionID->Data2, pgActionID->Data3,
+        pgActionID->Data4[0], pgActionID->Data4[1], pgActionID->Data4[2], pgActionID->Data4[3],
+        pgActionID->Data4[4], pgActionID->Data4[5], pgActionID->Data4[6], pgActionID->Data4[7]);
+
+    /* Write the information to the registry */
+    Res = WINTRUST_WriteProviderToReg(GuidString, Initialization  , psProvInfo->sInitProvider);
+    if (Res != ERROR_SUCCESS) WriteActionError = Res;
+    Res = WINTRUST_WriteProviderToReg(GuidString, Message         , psProvInfo->sObjectProvider);
+    if (Res != ERROR_SUCCESS) WriteActionError = Res;
+    Res = WINTRUST_WriteProviderToReg(GuidString, Signature       , psProvInfo->sSignatureProvider);
+    if (Res != ERROR_SUCCESS) WriteActionError = Res;
+    Res = WINTRUST_WriteProviderToReg(GuidString, Certificate     , psProvInfo->sCertificateProvider);
+    if (Res != ERROR_SUCCESS) WriteActionError = Res;
+    Res = WINTRUST_WriteProviderToReg(GuidString, CertCheck       , psProvInfo->sCertificatePolicyProvider);
+    if (Res != ERROR_SUCCESS) WriteActionError = Res;
+    Res = WINTRUST_WriteProviderToReg(GuidString, FinalPolicy     , psProvInfo->sFinalPolicyProvider);
+    if (Res != ERROR_SUCCESS) WriteActionError = Res;
+    Res = WINTRUST_WriteProviderToReg(GuidString, DiagnosticPolicy, psProvInfo->sTestPolicyProvider);
+    if (Res != ERROR_SUCCESS) WriteActionError = Res;
+    Res = WINTRUST_WriteProviderToReg(GuidString, Cleanup         , psProvInfo->sCleanupProvider);
+    if (Res != ERROR_SUCCESS) WriteActionError = Res;
+
+    /* Testing (by restricting access to the registry for some keys) shows that the last failing function
+     * will be used for last error.
+     * an error is the one used to propagate the last error. 
+     * If the flag WT_ADD_ACTION_ID_RET_RESULT_FLAG is set and there are errors when adding the action
+     * we have to return FALSE. Errors includes both invalid entries as well as registry errors.
+     * Testing also showed that one error doesn't stop the registry writes. Every action will be dealt with.
+     */
+
+    if (WriteActionError != ERROR_SUCCESS)
+    {
+        SetLastError(WriteActionError);
+
+        if (fdwFlags == WT_ADD_ACTION_ID_RET_RESULT_FLAG)
+            return FALSE;
+    }
+
+    return TRUE;
 }
 
 /***********************************************************************
- *              WINTRUST_RemoveProviderFromReg (WINTRUST.@)
+ *              WINTRUST_RemoveProviderFromReg
  *
  * Helper function for WintrustRemoveActionID
  *
diff --git a/dlls/wintrust/tests/register.c b/dlls/wintrust/tests/register.c
index 2a56c07..51804ac 100644
--- a/dlls/wintrust/tests/register.c
+++ b/dlls/wintrust/tests/register.c
@@ -70,47 +70,35 @@
     SetLastError(0xdeadbeef);
     ret = pWintrustAddActionID(NULL, 0, NULL);
     ok (!ret, "Expected WintrustAddActionID to fail.\n");
-    todo_wine
-    {
-        ok (GetLastError() == ERROR_INVALID_PARAMETER /* XP/W2K3 */ ||
-            GetLastError() == 0xdeadbeef              /* Win98/NT4/W2K */,
-            "Expected ERROR_INVALID_PARAMETER(W2K3) or 0xdeadbeef(Win98/NT4/W2K), got %ld.\n", GetLastError());
-    }
+    ok (GetLastError() == ERROR_INVALID_PARAMETER /* XP/W2K3 */ ||
+        GetLastError() == 0xdeadbeef              /* Win98/NT4/W2K */,
+        "Expected ERROR_INVALID_PARAMETER(W2K3) or 0xdeadbeef(Win98/NT4/W2K), got %ld.\n", GetLastError());
 
     /* NULL functions */
     SetLastError(0xdeadbeef);
     ret = pWintrustAddActionID(&ActionID, 0, NULL);
     ok (!ret, "Expected WintrustAddActionID to fail.\n");
-    todo_wine
-    {
-        ok (GetLastError() == ERROR_INVALID_PARAMETER /* XP/W2K3 */ ||
-            GetLastError() == 0xdeadbeef              /* Win98/NT4/W2K */,
-            "Expected ERROR_INVALID_PARAMETER(W2K3) or 0xdeadbeef(Win98/NT4/W2K), got %ld.\n", GetLastError());
-    }
+    ok (GetLastError() == ERROR_INVALID_PARAMETER /* XP/W2K3 */ ||
+        GetLastError() == 0xdeadbeef              /* Win98/NT4/W2K */,
+        "Expected ERROR_INVALID_PARAMETER(W2K3) or 0xdeadbeef(Win98/NT4/W2K), got %ld.\n", GetLastError());
 
     /* All OK (although no functions defined), except cbStruct is not set in ActionIDFunctions */
     SetLastError(0xdeadbeef);
     memset(&ActionIDFunctions, 0, sizeof(CRYPT_REGISTER_ACTIONID));
     ret = pWintrustAddActionID(&ActionID, 0, &ActionIDFunctions);
     ok (!ret, "Expected WintrustAddActionID to fail.\n");
-    todo_wine
-    {
-        ok (GetLastError() == ERROR_INVALID_PARAMETER /* XP/W2K3 */ ||
-            GetLastError() == 0xdeadbeef              /* Win98/NT4/W2K */,
-            "Expected ERROR_INVALID_PARAMETER(W2K3) or 0xdeadbeef(Win98/NT4/W2K), got %ld.\n", GetLastError());
-    }
+    ok (GetLastError() == ERROR_INVALID_PARAMETER /* XP/W2K3 */ ||
+        GetLastError() == 0xdeadbeef              /* Win98/NT4/W2K */,
+        "Expected ERROR_INVALID_PARAMETER(W2K3) or 0xdeadbeef(Win98/NT4/W2K), got %ld.\n", GetLastError());
 
     /* All OK (although no functions defined) and cbStruct is set now */
     SetLastError(0xdeadbeef);
     memset(&ActionIDFunctions, 0, sizeof(CRYPT_REGISTER_ACTIONID));
     ActionIDFunctions.cbStruct = sizeof(CRYPT_REGISTER_ACTIONID);
     ret = pWintrustAddActionID(&ActionID, 0, &ActionIDFunctions);
-    todo_wine
-    {
-        ok (ret, "Expected WintrustAddActionID to succeed.\n");
-        ok (GetLastError() == ERROR_INVALID_PARAMETER /* W2K */,
-            "Expected ERROR_INVALID_PARAMETER, got %ld.\n", GetLastError());
-    }
+    ok (ret, "Expected WintrustAddActionID to succeed.\n");
+    ok (GetLastError() == ERROR_INVALID_PARAMETER,
+        "Expected ERROR_INVALID_PARAMETER, got %ld.\n", GetLastError());
 
     /* All OK and all (but 1) functions are correctly defined. The DLL and entrypoints
      * are not present.
@@ -127,12 +115,9 @@
     ActionIDFunctions.sCleanupProvider = DummyProvider;
     SetLastError(0xdeadbeef);
     ret = pWintrustAddActionID(&ActionID, 0, &ActionIDFunctions);
-    todo_wine
-    {
-        ok (ret, "Expected WintrustAddActionID to succeed.\n");
-        ok (GetLastError() == ERROR_INVALID_PARAMETER,
-            "Expected ERROR_INVALID_PARAMETER, got %ld.\n", GetLastError());
-    }
+    ok (ret, "Expected WintrustAddActionID to succeed.\n");
+    ok (GetLastError() == ERROR_INVALID_PARAMETER,
+        "Expected ERROR_INVALID_PARAMETER, got %ld.\n", GetLastError());
 
     /* All OK and all functions are correctly defined. The DLL and entrypoints
      * are not present.
@@ -149,12 +134,9 @@
     ActionIDFunctions.sCleanupProvider = DummyProvider;
     SetLastError(0xdeadbeef);
     ret = pWintrustAddActionID(&ActionID, 0, &ActionIDFunctions);
-    todo_wine
-    {
-        ok (ret, "Expected WintrustAddActionID to succeed.\n");
-        ok (GetLastError() == 0xdeadbeef,
-            "Expected 0xdeadbeef, got %ld.\n", GetLastError());
-    }
+    ok (ret, "Expected WintrustAddActionID to succeed.\n");
+    ok (GetLastError() == 0xdeadbeef,
+        "Expected 0xdeadbeef, got %ld.\n", GetLastError());
 
     SetLastError(0xdeadbeef);
     ret = pWintrustRemoveActionID(&ActionID);
diff --git a/include/wintrust.h b/include/wintrust.h
index 2e7917d..b04e134 100644
--- a/include/wintrust.h
+++ b/include/wintrust.h
@@ -297,6 +297,7 @@
 
 #include <poppack.h>
 
+#define WT_ADD_ACTION_ID_RET_RESULT_FLAG 1
 
 #ifdef __cplusplus
 extern "C" {