[PATCH] winspool: implement EnumFormsA/W for form level 1, add a few builtin forms

Marcel Partap mpartap at gmx.net
Sun Dec 9 12:48:46 CST 2007


---
 dlls/winspool.drv/info.c |  269 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 263 insertions(+), 6 deletions(-)

diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c
index 236d77d..27fd31d 100644
--- a/dlls/winspool.drv/info.c
+++ b/dlls/winspool.drv/info.c
@@ -139,6 +139,25 @@ typedef struct {
     LPCWSTR  versionsubdir;
 } printenv_t;
 
+/* ############ FORMS ############ */
+typedef struct {
+    SIZEL size;
+    RECTL area;
+    DWORD formorder;
+    DWORD flags;
+} form_regentry_t;
+
+struct builtin_form {
+    WCHAR           formname[CCHFORMNAME];
+    form_regentry_t formdata;
+};
+
+static const struct builtin_form builtin_forms[] = {
+    {{'L','e','t','t','e','r',0}, {{216000,279000}, {0,0,216000,279000}, 0, FORM_BUILTIN}},
+    {{'A','3',0}, {{297000,420000}, {0,0,297000,420000}, 0, FORM_BUILTIN}},
+    {{'A','4',0}, {{210000,297000}, {0,0,210000,297000}, 0, FORM_BUILTIN}},
+    {{'A','5',0}, {{148000,210000}, {0,0,148000,210000}, 0, FORM_BUILTIN}} };
+
 /* ############################### */
 
 static struct list monitor_handles = LIST_INIT( monitor_handles );
@@ -163,6 +182,12 @@ static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
                                   'E','n','v','i','r','o','n','m','e','n','t','s','\\',
                                   '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
 
+static const WCHAR FormsW[] = { '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','\\',
+                                'F','o','r','m','s',0 };
+
 static const WCHAR MonitorsW[] =  { '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','\\',
@@ -6991,25 +7016,257 @@ BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrin
 }
 
 /******************************************************************************
+ * calculate needed size then write form to provided buffer if big enough (INTERNAL)
+ */
+static void write_form_to_buffer(LPWSTR formname, const form_regentry_t *databuffer, DWORD formnumber, LPBYTE *pBuffer, LPBYTE *strptr, DWORD cbBuf, DWORD *needed, BOOL unicode)
+{
+    DWORD         forminfosize = sizeof(FORM_INFO_1W);
+    DWORD         formnamesize;
+    PFORM_INFO_1W pFI;
+
+    if (unicode) formnamesize = (strlenW(formname)+1)*sizeof(WCHAR);
+    else formnamesize = WideCharToMultiByte(CP_ACP, 0, formname, -1, NULL, 0, NULL, NULL);
+    *needed += formnamesize + forminfosize;
+
+    /* don't write beyond buffer size */
+    if (*pBuffer && cbBuf >= *needed)
+    {
+        pFI = (PFORM_INFO_1W)*pBuffer;
+        if (unicode)
+        {
+            TRACE("%p: writing FORM_INFO_1W #%d\n", *pBuffer, formnumber);
+            lstrcpyW((LPWSTR)*strptr, formname);
+        }
+        else
+        {
+            TRACE("%p: writing FORM_INFO_1A #%d\n", *pBuffer, formnumber);
+            WideCharToMultiByte(CP_ACP, 0, formname, -1, (LPSTR)*strptr, formnamesize, NULL, NULL);
+        }
+
+        /* FORM_INFO_1A/W identical except type of string pName points to */
+        pFI->pName = (LPWSTR)*strptr;
+        pFI->Size = databuffer->size;
+        pFI->ImageableArea = databuffer->area;
+        /* there are two incarnations of form registry entries (with and without DWORD formorder)  */
+        /* Wine uses only the former one but handle the other one by offsetting flags by one DWORD */
+        pFI->Flags = (sizeof(form_regentry_t) == sizeof(form_regentry_t)) ? databuffer->flags : databuffer->formorder;
+    }
+    *pBuffer += forminfosize;
+    *strptr += formnamesize;
+}
+
+/*****************************************************************************
+ * enumerate the local forms (INTERNAL)
+ *
+ * returns the needed size (in bytes) for pForm
+ * and  *lpreturned is set to number of entries returned in pForm
+ *
+ *NOTES:
+ * fixme: level 2 support missing
+ */
+static DWORD get_local_forms(DWORD level, LPBYTE pForm, DWORD cbBuf, LPDWORD lpreturned, BOOL unicode)
+{
+    HKEY    hformskey = NULL;
+    INT     i;
+    DWORD   index = 0;
+    DWORD   needed = 0;
+    WCHAR   formname[CCHFORMNAME+1];
+    DWORD   formnamelen = sizeof(formname);
+    DWORD   forminfosize;
+    DWORD   buffersize = sizeof(form_regentry_t);
+    LPBYTE  strptr;
+    DWORD   regtype;
+    DWORD   numentries;
+    form_regentry_t databuffer;
+
+    /* sizeof(FORM_INFO_1A) equals sizeof(FORM_INFO_1W) */
+    forminfosize = sizeof(FORM_INFO_1W);
+
+    /* set string pointer to after calculated size of form structures */
+    numentries = *lpreturned;
+    strptr = pForm + numentries * forminfosize;
+
+    /* create the "Forms"-key if non-existent and receive a handle to it */
+    if (RegCreateKeyW(HKEY_LOCAL_MACHINE, FormsW, &hformskey) == ERROR_SUCCESS)
+    {
+        /* handle built-in forms */
+        numentries = sizeof(builtin_forms)/sizeof(builtin_forms[0]);
+        for (i = 0; i < numentries; i++) {
+            write_form_to_buffer(builtin_forms[i].formname, &builtin_forms[i].formdata, i, &pForm, &strptr, cbBuf, &needed, unicode);
+        }
+        /* scan and spit out all form entries */
+        while (RegEnumValueW(hformskey, index, formname, &formnamelen, NULL,
+                             &regtype, (LPBYTE)&databuffer, &buffersize) == ERROR_SUCCESS)
+        {
+            if (formname[0])
+            {
+                numentries++;
+                write_form_to_buffer(formname, &databuffer, numentries, &pForm, &strptr, cbBuf, &needed, unicode);
+            }
+            index++;
+            formnamelen = sizeof(formname);
+            buffersize = sizeof(form_regentry_t);
+        }
+        RegCloseKey(hformskey);
+    }
+    *lpreturned = numentries;
+    TRACE("returned %d byte for %d entries\n", needed, numentries);
+    return needed;
+}
+
+/******************************************************************************
  *      EnumFormsA (WINSPOOL.@)
+ * same as EnumFormsW except unicode = FALSE
  */
 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
     DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
 {
-    FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD   needed = 0;
+    DWORD   numentries = 0;
+    BOOL    res = FALSE;
+    opened_printer_t *printer = NULL;
+
+    TRACE("(hPrinter = %p, Level = %d, pForm = %p, cbBuf = %u, pcbNeeded = %p, pcReturned = %p) called\n",
+          hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
+
+    /* fixme: if valid ignore hPrinter: return all forms for every printer */
+    if (!(printer = get_opened_printer(hPrinter)))
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        goto efA_cleanup;
+    }
+
+    /* valid levels are 1 and 2*/
+    if (Level != 2 && Level != 1)
+    {
+        SetLastError(ERROR_INVALID_LEVEL);
+        goto efA_cleanup;
+    }
+
+    if (Level == 2)
+    {
+        FIXME("level 2 not yet supported\n");
+        SetLastError(ERROR_INVALID_LEVEL);
+        goto efA_cleanup;
+    }
+
+    /* Scan all Forms */
+    numentries = 0;
+    needed = get_local_forms(Level, NULL, 0, &numentries, FALSE);
+
+    /* we calculated the needed buffersize. now do the error-checks */
+    if (cbBuf < needed)
+    {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        goto efA_cleanup;
+    }
+    if (!pForm)
+    {
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+        goto efA_cleanup;
+    }
+    if (!pcbNeeded || !pcReturned)
+    {
+        SetLastError(RPC_X_NULL_REF_POINTER);
+        goto efA_cleanup;
+    }
+
+    /* fill the Buffer with the forminfos*/
+    if ((needed = get_local_forms(Level, pForm, cbBuf, &numentries, FALSE)) == 0) res = FALSE;
+    else res = TRUE;
+
+efA_cleanup:
+    if (pcbNeeded)  *pcbNeeded = needed;
+    if (pcReturned) *pcReturned = numentries;
+
+    TRACE("returning %d with LastError = %u (%d byte for %d entries)\n",
+          res, GetLastError(), needed, numentries);
+    return (res);
 }
 
 /******************************************************************************
  *      EnumFormsW (WINSPOOL.@)
+ * enumerates available paper forms for specified printer
+ * 
+ * PARAMS
+ *  hPrinter   (I) handle to printer
+ *  Level      (I) type of returned form information data structure
+ *  pForm      (O) pointer to user supplied buffer
+ *  cbBuf      (I) size of buffer
+ *  pcbNeeded  (O) required/ used buffer space
+ *  pcReturned (O) number of returned forms
+ *
+ * RETURNS
+ *  Success: TRUE (non-zero value)
+ *  Failure: FALSE (0)
+ *
+ * NOTES
+ *  FORM_INFO_2* (not yet implemented)
  */
 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
     DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
 {
-    FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD   needed = 0;
+    DWORD   numentries = 0;
+    BOOL    res = FALSE;
+    opened_printer_t *printer = NULL;
+
+    TRACE("(hPrinter = %p, Level = %d, pForm = %p, cbBuf = %u, pcbNeeded = %p, pcReturned = %p) called\n",
+          hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
+
+    /* fixme: if valid ignore hPrinter: return all forms for every printer */
+    if (!(printer = get_opened_printer(hPrinter)))
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        goto efW_cleanup;
+    }
+
+    /* valid levels are 1 and 2*/
+    if (Level != 2 && Level != 1)
+    {
+        SetLastError(ERROR_INVALID_LEVEL);
+        goto efW_cleanup;
+    }
+
+    if (Level == 2)
+    {
+        FIXME("level 2 not yet supported\n");
+        SetLastError(ERROR_INVALID_LEVEL);
+        goto efW_cleanup;
+    }
+
+    /* Scan all Forms */
+    numentries = 0;
+    needed = get_local_forms(Level, NULL, 0, &numentries, TRUE);
+
+    /* we calculated the needed buffersize. now do the error-checks */
+    if (cbBuf < needed)
+    {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        goto efW_cleanup;
+    }
+    if (!pForm)
+    {
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+        goto efW_cleanup;
+    }
+    if (!pcbNeeded || !pcReturned)
+    {
+        SetLastError(RPC_X_NULL_REF_POINTER);
+        goto efW_cleanup;
+    }
+
+    /* fill the Buffer with the forminfos*/
+    if ((needed = get_local_forms(Level, pForm, cbBuf, &numentries, TRUE)) == 0) res = FALSE;
+    else res = TRUE;
+
+efW_cleanup:
+    if (pcbNeeded)  *pcbNeeded = needed;
+    if (pcReturned) *pcReturned = numentries;
+
+    TRACE("returning %d with LastError = %u (%d byte for %d entries)\n",
+          res, GetLastError(), needed, numentries);
+    return (res);
 }
 
 /*****************************************************************************
-- 
1.5.3.7


--------------040609060005070505070702--



More information about the wine-patches mailing list