Prev: VB6 vs DirectX
Next: VB6 - Vista - Mouse wheel
From: J French on 9 Feb 2007 03:28 On Thu, 08 Feb 2007 20:08:45 GMT, "mayayana" <mayayana1a(a)mindspring.com> wrote: > I've got another problem with C string arrays >that I'm hoping someome might shed some light on. >Attempting to create a CAB file with cabinet.dll, >the in parameter for the file list is: > >char **var or char *var[] > > It turns out that I can successfully send that array >as a null-delimited plain string, or as an array of >UDTs like so: > >Type CArr > Ab() as byte >End Type > > I start with a string thus: > >C:\WINDOWS\Desktop\Up\wed1-31.txt|C:\WINDOWS\Desktop\Up\fri2-2.txt|C:\WINDOW >S\Desktop\Up\sat2-3.txt|C:\WINDOWS\Desktop\Up\sun2-4.txt > > I then change the "|" to chr(0) and send it to >my C++ DLL. Using message boxes in my DLL, it >turns out that the first array member is fine. It's >the first file path, as expected. But the second array >member gets chopped just before the file name: > >C:\WINDOWS\Desktop\Up\ This is ringing bells, I wonder whether the author of the DLL is expecting the first entry to contain the full path and file name and subsequent entries to consist of just the pathless file name The lpstrFile of the OPENFILENAME structure returns <quote> Pointer to a buffer that contains a filename used to initialize the File Name edit control. The first character of this buffer must be NULL if initialization is not necessary. When the GetOpenFileName or GetSaveFileName function returns successfully, this buffer contains the drive designator, path, filename, and extension of the selected file. If the OFN_ALLOWMULTISELECT flag is set and the user selects multiple files, the buffer contains the current directory followed by the filenames of the selected files. </quote> It is possible that the DLL is designed to receive input directly from a buffer filled in by GetOpenFileName. Just a thought ...
From: Jim Mack on 9 Feb 2007 06:29 mayayana wrote: > including it for thoroughness. This is what VB calls: > > ----------------------------------------------------------- > int WINAPI MakeCAB(LPSTR sCABFileName, LPSTR sDestFolder, int > iNumFiles, char **afiles) Here's where my knowledge of C falls over, so this may be wrong information: It seems to me that you're treating **char and *char[] as exactly equivalent, and that probably isn't true. It's a bad idea to use MessageBox to debug, since the message box will only display up to the first NULL in any case -- even if you passed it the entire input string array, it would only show you the first string. Better to run this under a debugger and trace execution through the name-stripping code, etc. In any case, what you're doing in VB is correct, so I think this now has to move to a C group. -- Jim > { > int i; > > i = strlen(sDestFolder); > if ((i > 255) || (i < 3)) > { > return 1; // 1 - invalid cab destination path. > } > i = strlen(sCABFileName); > if (i < 5) > { > return 2; // 2 - invalid cab name. (Doesn't check for > extension validity.) > } > > if (iNumFiles < 1) > { > return 3; // 3 - no files. > } > > strcpy(sCABFol, sDestFolder); > strcpy(sCABName, sCABFileName); > > MessageBox(NULL, afiles[1], "2nd file path", MB_OK | > MB_ICONINFORMATION); > > // Strange thing here: this message box never shows. > > MessageBox(NULL, afiles[2], "3rd file path", MB_OK | > MB_ICONINFORMATION); > > if (test_fci(iNumFiles, &afiles[0]) == TRUE) > return 0; > else > return LRet; // LRet is a global. > } > > ------------------------------------------------------- > > that function calls this: > > BOOL test_fci(int num_files, char *file_list[]) > { > HFCI hfci; > ERF erf; > CCAB cab_parameters; > int i; > client_state cs; > > /* > * Initialise our internal state > */ > cs.total_compressed_size = 0; > cs.total_uncompressed_size = 0; > > set_cab_parameters(&cab_parameters); > > hfci = FCICreate( > &erf, > file_placed, > mem_alloc, > mem_free, > fci_open, > fci_read, > fci_write, > fci_close, > fci_seek, > fci_delete, > get_temp_file, > &cab_parameters, > &cs > ); > > > if (hfci == NULL) > { > LRet = (erf.erfOper + 10); > return FALSE; > } > > > // for each file in array... > for (i = 0; i < num_files; i++) > { > > char stripped_name[256]; > char spath[256]; > > strcpy(spath, file_list[i]); > /* > * Don't store the path name in the cabinet file! > */ > strip_path(spath, stripped_name); // strip off path. > > // this message box will return correctly for first index, > // but for second index it returns "" for stripped_name > // and only folder path for file_list[i] > > MessageBox(NULL, file_list[i], stripped_name, MB_OK | > MB_ICONINFORMATION); > > if (FALSE == FCIAddFile( > hfci, > file_list[i], /* file to add */ > stripped_name, /* file name in cabinet file */ > FALSE, /* file is not executable */ > get_next_cabinet, > progress, > get_open_info, > tcompTYPE_MSZIP)) > { > > (void) FCIDestroy(hfci); > LRet = (erf.erfOper + 20); > return FALSE; > } > } > -------------------------------------------------- > .....etc..... The spath variable is not necessary, but > I added it in just to make sure that the strip_path > sub was not somehow affecting the next iteration. > strip_path takes a path string and returns the file name > in the 2nd parameter. > ------------------------------------------------ > > > On the VB side, the following is my current > code, which seems to clip the file name on the > second array member. The sList string is exactly as > I posted it earlier - 4 file names. > (With the array of UDTs: I'm not sure what I was > thinking about that. I tried that method but it didn't > work.) > > Private Declare Function MakeCAB Lib "jcabmake.dll" (ByVal > sCABFileName As String, ByVal sDestFolder As String, ByVal iNumFiles > As Long, AFileList As String) As Long > > > Private sList As String > > Private Sub Command1_Click() > Dim LNum As Long > > sList = Text4.Text > A1 = Split(sList, "|") > LNum = UBound(A1) + 1 > > sList = Replace(sList, "|", Chr(0)) > sList = sList & Chr(0) > > '-- sName and sDest here are file name and > '-- destination folder. That all works OK. > > LRet = MakeCAB(sName, sDest, LNum, sList) > End Sub.
From: mayayana on 9 Feb 2007 09:53 > This is ringing bells, I wonder whether the author of the DLL is > expecting the first entry to contain the full path and file name and > subsequent entries to consist of just the pathless file name > I guess that's possible. The cabinet.dll operation expects a full path, but the code is adapted from an MS command line sample. In that case, the command line comes through as: testprogram.exe file1.txt file2.txt .....etc... And the MS sample code starts reading at array(1). It may be that the sample program is just setting current directory and sending file names. That's odd, though, because the cabinet.dll docs specifically say that the FCIAddFile parameter should be a full path. That would also mean that all of the CAB files have to be in the same folder. And that still doesn't explain why my path is actually coming through chopped, before it even gets to the cabinet.dll ops. Anyway, thanks. Maybe I'll experiment with building the path on the DLL side.
From: mayayana on 9 Feb 2007 10:01 > ----------------------------------------------------------- > int WINAPI MakeCAB(LPSTR sCABFileName, LPSTR sDestFolder, int > iNumFiles, char **afiles) Here's where my knowledge of C falls over, so this may be wrong information: It seems to me that you're treating **char and *char[] as exactly equivalent, and that probably isn't true. ----------- Thanks for the effort, anyway. On the declare, I actually read in one place that char **var and char *[] are the same thing - a matter of taste. And they do seem to work the same way. I'm still not entirely clear about the char type variations, but there's obviously something I'm not getting. I get the exact same partial result with a null-delimited string as I do with a string array, and the way I figure it, a null- delimited string is a char multi-dimensional array that's lacking an accurate declaration. (like: var [4] [256] ) The array of strings seems like it *should* be right, because I declare the array as string, so I'm passing a pointer to char array pointers (once VB gets through converting the string). But the C++ side is happy to half-digest anything, it seems. > In any case, what you're doing in VB is correct, so I think > this now has to move to a C group. I suspect they'd only sniff at me haughtily there. I might just as well ask for kind help in a Linux group. :)
From: Ralph on 9 Feb 2007 10:39
"mayayana" <mayayana1a(a)mindspring.com> wrote in message news:d10zh.74$Jl.28(a)newsread3.news.pas.earthlink.net... > > > ----------------------------------------------------------- > > int WINAPI MakeCAB(LPSTR sCABFileName, LPSTR sDestFolder, int > > iNumFiles, char **afiles) > > > Here's where my knowledge of C falls over, so this may be wrong information: > It seems to me that you're treating **char and *char[] as exactly > equivalent, and that probably isn't true. > > ----------- > > Thanks for the effort, anyway. On the declare, I actually > read in one place that char **var and char *[] are the same > thing - a matter of taste. And they do seem to work the > same way. > > I'm still not entirely clear about the char type variations, > but there's obviously something I'm not getting. I get > the exact same partial result with a null-delimited string > as I do with a string array, and the way I figure it, a null- > delimited string is a char multi-dimensional array that's > lacking an accurate declaration. (like: var [4] [256] ) > > The array of strings seems like it *should* be right, > because I declare the array as string, so I'm passing > a pointer to char array pointers (once VB gets through > converting the string). But the C++ side is happy to > half-digest anything, it seems. > > > In any case, what you're doing in VB is correct, so I think > > this now has to move to a C group. > > I suspect they'd only sniff at me haughtily there. > I might just as well ask for kind help in a Linux group. :) > **var and *var[], ( and var[][] for completness )are functionally equivalent in a declaration, as ... *var == &var[0], thus *var == var Or to muddy the waters even further ... char var[i] == *(var + (sizeof (char) * i)) thus var[i][j] == *(var[i] + (sizeof(char) + j)), or *( *(var + (sizeof(char) * i)) + (sizeof(char) * j)) It is just instructions to the compiler on how to stomp around on the buffer. Whenever strings appear to be mysteriously 'chopped' in C it is most often caused by embedded nuls. -ralph |