[2/5] dinput: SetActionMap saving simple configurations to an .ini file (try 2)

Lucas Fialho Zawacki lfzawacki at gmail.com
Mon Jan 9 11:18:34 CST 2012


From: Lucas Fialho Zawacki <lfzawacki at gmail.com>

Just the action mapping GUID, number of actions and the time the mapping was applied.

The helper function heap_printfW was copied from winemenubuilder.c

Changes since first try:

* Using StringFromCLSID instead of debugstr_guid
* Marked WCHAR arrays as static
* Error handling for all the calls of heap_printfW and _write_private_profile_intW
* Explicitly creating the mapping files directory and testing if it is created succesfully
* Had to include shell32 for SHCreateDirectoryExW

---
 dlls/dinput/Makefile.in      |    2 +-
 dlls/dinput/device.c         |  117 ++++++++++++++++++++++++++++++++++++++++++
 dlls/dinput/dinput_main.c    |   45 ++++++++++++++++
 dlls/dinput/dinput_private.h |    3 +
 4 files changed, 166 insertions(+), 1 deletions(-)

diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in
index 1be48c4..7c5e80c 100644
--- a/dlls/dinput/Makefile.in
+++ b/dlls/dinput/Makefile.in
@@ -1,6 +1,6 @@
 MODULE    = dinput.dll
 IMPORTLIB = dinput
-IMPORTS   = dxguid uuid comctl32 ole32 user32 advapi32
+IMPORTS   = dxguid uuid comctl32 ole32 user32 advapi32 shell32
 EXTRALIBS = @IOKITLIB@
 
 C_SRCS = \
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index f5b7b4b..0d29844 100644
--- a/dlls/dinput/device.c
+++ b/dlls/dinput/device.c
@@ -28,6 +28,7 @@
 
 #include <stdarg.h>
 #include <string.h>
+#include <shlobj.h>
 #include "wine/debug.h"
 #include "wine/unicode.h"
 #include "windef.h"
@@ -598,6 +599,111 @@ static DWORD semantic_to_obj_id(IDirectInputDeviceImpl* This, DWORD dwSemantic)
     return type | (0x0000ff00 & (obj_instance << 8));
 }
 
+/*
+ * _write_private_profile_int_W
+ * An utility function to write an integer, with a specified format, to an .ini file.
+ */
+static BOOL _write_private_profile_intW(const char *format, WCHAR* section, WCHAR* key, int value, WCHAR* file)
+{
+    WCHAR* value_str = heap_printfW(format, value);
+
+    if (value_str == NULL)
+        return FALSE;
+
+    WritePrivateProfileStringW(section, key, value_str, file);
+    HeapFree(GetProcessHeap(), 0, value_str);
+
+    return TRUE;
+}
+
+/*
+ * _get_mapping_path
+ * For a given username and device name, returns the filename with path of the
+ * mapping settings files.
+ * The caller has to free the returned string.
+ */
+WCHAR* _get_mapping_path(const WCHAR *device, const WCHAR *username)
+{
+    static WCHAR path[] = {
+        '%','C','o','m','m','o','n','P','r','o','g','r','a','m','F','i','l','e','s','%','\\',
+        'D','i','r','e','c','t','X','\\',
+        'D','i','r','e','c','t','I','n','p','u','t','\\',
+        'U','s','e','r',' ','M','a','p','s','\0'};
+    WCHAR *expanded_path = NULL, *ret = NULL;
+    DWORD path_ret;
+    int expanded_path_size;
+
+    expanded_path_size = ExpandEnvironmentStringsW(path, NULL, 0);
+    expanded_path = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*expanded_path_size);
+    ExpandEnvironmentStringsW(path, expanded_path, expanded_path_size);
+
+    /* Explicitly create the directory where the mappings will reside */
+    path_ret = SHCreateDirectoryExW(NULL, expanded_path, NULL);
+
+    /* Only return a path if the creation was successfull */
+    if (path_ret == ERROR_ALREADY_EXISTS || ERROR_SUCCESS)
+        /* The filename is like this: PATH\TO\FILE\USERNAMEX_DEVICEX_0.INI */
+        ret = heap_printfW("%s\\%sX_%sX_0.INI", expanded_path, username, device);
+
+    /* Unallocate */
+    HeapFree(GetProcessHeap(), 0, expanded_path);
+
+    return ret;
+}
+
+static HRESULT _save_mapping_settings(IDirectInputDevice8W *iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUsername)
+{
+    static WCHAR mapexists[] = {'M','a','p','E','x','i','s','t','s','\0'};
+    static WCHAR numactions[] = {'N','u','m','A','c','t','i','o','n','\0'};
+    DIDEVICEINSTANCEW didev;
+    SYSTEMTIME stime;
+    FILETIME ftime;
+    HRESULT ret;
+    WCHAR *map_path = NULL, *app_section = NULL, *guid_str = NULL, *time_high = NULL, *time_low = NULL;
+
+    didev.dwSize = sizeof(didev);
+    IDirectInputDevice8_GetDeviceInfo(iface, &didev);
+
+    map_path = _get_mapping_path(didev.tszInstanceName, lpszUsername);
+
+    /* Guid and Timestamp */
+    StringFromCLSID(&lpdiaf->guidActionMap, (LPOLESTR*) &guid_str);
+
+    time_high = heap_printfW("%s.TimestampHigh", guid_str);
+    time_low = heap_printfW("%s.TimestampLow", guid_str);
+
+    /* Device app section */
+    /* Something like this: [DEVICENAME.Application.GUID.Genre.NUMBER] */
+    app_section = heap_printfW("%s.Application.%s.Genre.%d", didev.tszInstanceName, guid_str, HIBYTE(HIWORD(lpdiaf->dwGenre)));
+
+    if (time_high == NULL || time_low == NULL || map_path == NULL || app_section == NULL)
+    {
+        ret = DI_SETTINGSNOTSAVED;
+        goto cleanup;
+    }
+
+    GetSystemTime(&stime);
+    SystemTimeToFileTime(&stime, &ftime);
+
+    /* Write everything to the files */
+    _write_private_profile_intW("0x%08x", didev.tszInstanceName, time_high, ftime.dwHighDateTime, map_path);
+    _write_private_profile_intW("0x%08x", didev.tszInstanceName, time_low, ftime.dwLowDateTime, map_path);
+
+    _write_private_profile_intW("%d", app_section, mapexists, 1, map_path);
+    _write_private_profile_intW("%d", app_section, numactions, lpdiaf->dwNumActions, map_path);
+
+    ret = DI_OK;
+
+    /* Unallocate everything */
+    cleanup:
+    HeapFree(GetProcessHeap(), 0, map_path);
+    HeapFree(GetProcessHeap(), 0, guid_str);
+    HeapFree(GetProcessHeap(), 0, time_high);
+    HeapFree(GetProcessHeap(), 0, time_low);
+
+    return ret;
+}
+
 HRESULT _build_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags, DWORD devMask, LPCDIDATAFORMAT df)
 {
     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
@@ -650,6 +756,8 @@ HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, L
     DIOBJECTDATAFORMAT *obj_df = NULL;
     DIPROPDWORD dp;
     DIPROPRANGE dpr;
+    WCHAR username[MAX_PATH];
+    DWORD username_size = MAX_PATH;
     int i, action = 0, num_actions = 0;
     unsigned int offset = 0;
 
@@ -722,6 +830,15 @@ HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, L
         IDirectInputDevice8_SetProperty(iface, DIPROP_BUFFERSIZE, &dp.diph);
     }
 
+    /* Retrieve logged user name if necessary */
+    if (lpszUserName == NULL)
+        GetUserNameW(username, &username_size);
+    else
+        lstrcpynW(username, lpszUserName, MAX_PATH);
+
+    /* Save the settings to disk */
+    _save_mapping_settings(iface, lpdiaf, username);
+
     return IDirectInputDevice8WImpl_SetActionMap(iface, lpdiaf, lpszUserName, dwFlags);
 }
 
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c
index 6350a18..f7c1786 100644
--- a/dlls/dinput/dinput_main.c
+++ b/dlls/dinput/dinput_main.c
@@ -340,6 +340,51 @@ static DWORD _diactionformat_priorityW(LPDIACTIONFORMATW lpdiaf, DWORD genre)
     return priorityFlags;
 }
 
+/*
+ * heap_printfW
+ *
+ * An utility function that acts just like sprintfW, but returns a heap allocated WCHAR string.
+ * To make the code that uses it more readable the format is accepted as a CHAR string, but note
+ * that other strings that are eventually used as parameters should be WCHAR.
+ * The caller has to free the returned string.
+ */
+WCHAR* heap_printfW(const char *format, ...)
+{
+    va_list args;
+    int size = 512*sizeof(WCHAR), format_size;
+    WCHAR *buffer, *ret, *formatW = NULL;
+    int n;
+
+    format_size = MultiByteToWideChar(CP_ACP, 0, format, -1, formatW, 0);
+    formatW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*format_size);
+    MultiByteToWideChar(CP_ACP, 0, format, -1, formatW, format_size);
+
+    va_start(args, format);
+    while (1)
+    {
+        buffer = HeapAlloc(GetProcessHeap(), 0, size);
+        if (buffer == NULL)
+            break;
+        n = vsnprintfW(buffer, size, formatW, args);
+        if (n == -1)
+            size *= 2;
+        else if (n >= size)
+            size = n + 1;
+        else
+            break;
+        HeapFree(GetProcessHeap(), 0, buffer);
+    }
+    va_end(args);
+
+    if (buffer == NULL) return NULL;
+    ret = HeapReAlloc(GetProcessHeap(), 0, buffer, sizeof(WCHAR)*(strlenW(buffer)+1) );
+    if (ret == NULL) ret = buffer;
+
+    HeapFree(GetProcessHeap(), 0, formatW);
+
+    return ret;
+}
+
 /******************************************************************************
  *	IDirectInputA_EnumDevices
  */
diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h
index 8efb42e..c4fbf70 100644
--- a/dlls/dinput/dinput_private.h
+++ b/dlls/dinput/dinput_private.h
@@ -70,6 +70,9 @@ extern void _copy_diactionformatWtoA(LPDIACTIONFORMATA, LPDIACTIONFORMATW) DECLS
 
 extern HRESULT _configure_devices(IDirectInput8W *iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) DECLSPEC_HIDDEN;
 
+extern WCHAR* heap_printfW(const char *format, ...) DECLSPEC_HIDDEN;
+extern WCHAR* _get_mapping_path(const WCHAR *device, const WCHAR *username) DECLSPEC_HIDDEN;
+
 #define IS_DIPROP(x)    (((ULONG_PTR)(x) >> 16) == 0)
 
 #define DIKEYBOARD_MASK    0x81000000
-- 
1.7.0.4




More information about the wine-patches mailing list