C function to export text from a ListView into a text file with separators






3.80/5 (8 votes)
Win32 API using C - no MFC.
Introduction
You can find plenty of C++ and/or MFC code to deal with your ListView
controls, but maybe not enough pure C and API (SDK) code. This code snippet consists of only one C function (fExportListView
) that outputs the text content of a ListView
control into a newly created text file (with fields separated). The output text file can be imported into a spreadsheet software such as MS Excel, or into a database. Any reader interested in thorough explanations (only SDK, no MFC) can read the excellent article by Bengi (titled 'Using ListView control under Win32 API').
This is a first attempt at proposing C and API code - maybe completely useless? However, if you are interested in simple 'insert ListView
item' or 'insert ListView
column' functions, just let me know and I will upload those too, if they are needed.
Background
You should be familiar with C language and C program compiling, including Win32 API. Whether you use MFC or not, you should know about API. Therefore, reading Charles Petzold's book "Programming Windows" (published by Microsoft Press) is quite mandatory. By the way, thank you so much for your explanations and inspiring examples, Mr. Petzold.
Using the code
I assume you have declared, created, (re)sized and filled (with text) a ListView
control (i.e., a window of class WC_LISTVIEW
, with style, e.g., WS_BORDER | WS_CHILD | WS_VISIBLE | LVS_REPORT
). See reference on CreateWindowEx
in MSDN, and/or include the ListView
in your Visual Studio project.
Bear in mind that in a ListView
, you deal with columns, items and subitems. One of the columns contains only items (usually, the leftmost column), all the other columns contain only subitems. So, for a given 'line' in your ListView
, the LVM_GETITEMTEXT
message will copy text from:
- an item when the
iSubItem
member of theLVITEM
struct
equals zero, or - from a subitem when
iSubItem
is greater than zero.
See the code below and try it out.
The function is really simple, and comes with embedded comments explaining what it does step by step. However, here are some elements:
Declaration of the function:
int fExportListView(HWND hwndListView, FILE *filehandle, unsigned char *sFileName, char cSep, long lLines, long lCols);
The parameters to the function:
hwndListView
is the handle for yourListView
child windowfilehandle
is the pointer to yourFILE
structuresFileName
is the pointer to the 'string' that is your filenamecSep
is the character you want as a separator between fieldslLines
andlCols
are the numbers of lines and columns (respectively) in theListView
You might also need these include
s:
#include <windows.h> #include <stdio.h> #include <commctrl.h> (etc...)
C language background: functions such as sprintf()
, fprintf()
, memset()
, fopen()
, fclose()
, pointers and arrays.
API background: functions such as SendMessage()
, MessageBox()
and a struct
called LVITEM
.
Call this function, e.g., like this:
fExportListView(hwndLV, f, "fExportListView_tab.txt", 9, 10, 5);
fExportListView(hwndLV, f, "fExportListView_pipe.txt", '|', 20, 8);
with parameters of the same types as those described above - and properly declared someplace.
Return values of the function: 0 if problem or error occurs, 1 if OK.
Here is the code itself:
int fExportListView(HWND hwndListView, FILE *filehandle, unsigned char *sFileName, char cSep, long lLines, long lCols) { /********************* * Local declarations * *********************/ // LVITEM struct (see MSDN for content) : LVITEM lvi; // Max length of string into pszText member of LVITEM struct : long lMAX = 5000; // String buffer for pszText member of LVITEM struct : unsigned char LVtext[lMAX]; // To appear in the caption of the MessageBox : static unsigned char *sYourApplicationsName = "You fill that in with your app name :)"; // Error string you can use to 'MessageBox' and/or to 'fprintf' // into a logfile - a reasonable thing to do :) unsigned char sErrorString[lMAX]; // Long integers for various tasks : long i, j; /************************* * Minimum error checking * *************************/ // Checking ListView handle : if (hwndListView == NULL) { sprintf(sErrorString, "Handle of ListView NULL (fExportListView)"); // Your good old Windows message box : MessageBox(NULL, (LPSTR) sErrorString, (LPSTR) sYourApplicationsName, MB_OK | MB_ICONEXCLAMATION); return(0); } // Checking number of lines against parameter value : i = SendMessage((HWND) hwndListView, (UINT) LVM_GETITEMCOUNT, (WPARAM) 0, (LPARAM) 0); if (lLines != i) { sprintf(sErrorString, "%ld lines in ListView != %ld as" " parameter (fExportListView)", i, lLines); MessageBox(NULL, (LPSTR) sErrorString, (LPSTR) sYourApplicationsName, MB_OK | MB_ICONEXCLAMATION); return(0); } // Checking whether ListView empty : if (i == 0) { sprintf(sErrorString, "ListView empty (fExportListView)"); MessageBox(NULL, (LPSTR) sErrorString, (LPSTR) sYourApplicationsName, MB_OK | MB_ICONEXCLAMATION); return(0); } // Opening - rather creating - output file in write mode // (caution : overwrites a file with the same 'sFileName') : filehandle = fopen(sFileName, "w"); if (filehandle == NULL) { sprintf(sErrorString, "Error occurred while creating" " file %s (w mode) (fExportListView)", sFileName); MessageBox(NULL, (LPSTR) sErrorString, (LPSTR) sYourApplicationsName, MB_OK | MB_ICONEXCLAMATION); return(0); } /************************************************************* * Use a LVITEM struct to collect some text from the ListView * *************************************************************/ for (i=0; i<lLines; i++) { memset(&lvi, 0, sizeof(lvi)); // Clean up before action // Fill in the members of the LVITEM struct : lvi.mask = LVIF_TEXT; // Minimum here to take care of the pszText member // - see other LVIF_xxx constants in MSDN lvi.state = 0; lvi.stateMask = 0; // lvi.iSubItem : not here, see 'j' loop below lvi.cchTextMax = lMAX - 1; // Length of string to be copied into pszText member lvi.pszText = LVtext; // String buffer for pszText member // Nota bene : starts at zero (item) and ends at 'lCols' (last subitem) : for (j=0; j<=lCols; j++) { // Important member of LVITEM struct you // need to fill in (j=0 : item; j>0 : subitem) : lvi.iSubItem = j; // Retrieve the text in an item or a subitem of line 'i' : SendMessage(hwndListView, LVM_GETITEMTEXT, (WPARAM) i, (LPARAM) &lvi); if (filehandle != NULL) { // No separator at the beginning of a line (here, at item level) ... if (j == 0) fprintf(filehandle, "%s", LVtext); // ... only between two consecutive fields (here, at subitem level) : else fprintf(filehandle, "%c%s", cSep, LVtext); } } // End of line, Windows style i.e. carriage return // (implicit) plus new line (explicit) : if (filehandle != NULL) fprintf(filehandle, "\n"); } /******************************* * Close the output text file * * and return from the function * *******************************/ if (filehandle != NULL) fclose(filehandle); return(1); }
History
- December 8, 2004: version 1 of the function.