Prev: VB6 vs DirectX
Next: VB6 - Vista - Mouse wheel
From: mayayana on 8 Feb 2007 15:08 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\ Very weird. If there's only 1 file I'll successfully get a CAB produced, but with a second file it fails because the path is not valid for the 2nd file. The second file path is chopped even if I check it first thing after receiving the array in the DLL call!. I figure this must be an obvious thing I'm overlooking, or maybe something about C++ that I don't know. Grabbing at straws I tried doubling the "\" to "\\", but that's not the problem.
From: Jim Mack on 8 Feb 2007 15:37 Since there's no obvious reason why that would happen, it'd help if you showed us exactly how you're declaring the function that you send these strings to, and the code that formats the string and sends it along. For one thing, an array of a UDT containing dynamic byte arrays is not even remotely similar to char *var[] and could never substitute for a single VB string, so I don't think we're getting a clear picture of what's going on. I take it that your DLL is just a wrapper, and that it's passing the VB arguments along to the underlying CAB DLL? Have you debugged this at that level to see exactly what's getting to the CAB DLL? -- Jim Mack MicroDexterity Inc www.microdexterity.com mayayana 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\ > > Very weird. If there's only 1 file I'll successfully get a > CAB produced, but with a second file it fails because > the path is not valid for the 2nd file. The second file path > is chopped even if I check it first thing after receiving the > array in the DLL call!. I figure this must be an obvious thing > I'm overlooking, or maybe something about C++ that I don't > know. Grabbing at straws I tried doubling the "\" to "\\", but > that's not the problem.
From: mayayana on 8 Feb 2007 19:32 Since there's no obvious reason why that would happen, it'd help if you showed us exactly how you're declaring the function that you send these strings to, and the code that formats the string and sends it along. For one thing, an array of a UDT containing dynamic byte arrays is not even remotely similar to char *var[] and could never substitute for a single VB string, so I don't think we're getting a clear picture of what's going on. I take it that your DLL is just a wrapper, and that it's passing the VB arguments along to the underlying CAB DLL? Have you debugged this at that level to see exactly what's getting to the CAB DLL? ------------------------------------------- Yes, it's based on the MS sample from the CAB SDK, "testfci". I've put in message boxes at various places in my DLL. As for cabinet.dll, my call is returning 21, which is my own personal code for a combination of two things: The call failed with this error: "Failure opening file to be stored in cabinet" and it failed during the call to FCIAddFile. Sorry about the volume of code here. It's awkward because there's quite a bit interconnected. Much of the code in this function is not relevant, but I'm including it for thoroughness. This is what VB calls: ----------------------------------------------------------- int WINAPI MakeCAB(LPSTR sCABFileName, LPSTR sDestFolder, int iNumFiles, char **afiles) { 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 8 Feb 2007 22:20 Footnote: I had said before that I had an array of byte arrays working. I had that mixed up. What worked was this: '-- using a string array instead of a null-delimited string. A1 = Split(sList, "|") LNum = UBound(A1) + 1 '-- sList = Replace(sList, "|", Chr(0)) '-- sList = sList & Chr(0) ReDim AAsc(LNum) As String For i2 = 0 To LNum - 1 AAsc(i2) = A1(i2) Next AAsc(LNum) = vbNullChar '-- LRet = MakeCAB(sName, sDest, LNum, sList) '-- AAsc is an array declared as String and the MakeCAB last '-- parameter is declared as Any in that case. I thought that was "-- interesting: The C++ '-- side is getting an array of c string pointers, which makes '-- sense. But what surprises me is that it somehow receives '-- a null-delimited string in the same way. Even though the former '-- is an array of string pointers (pointer to pointer) while '-- the latter is a pointer to a string, both have the exact same result, '-- with array(0) getting through as a file path while array(1) '-- gets through as the parent folder path. LRet = MakeCAB(sName, sDest, LNum, AAsc(0))
From: Jim Mack on 8 Feb 2007 22:42
mayayana wrote: I didn't have time to look at your previous, but until I do, you may recall what I said earlier: you might think that just passing element 0 of a string array would work, but it doesn't -- you'll get the first string and that's all. Anything else is a coincidence. The only thing that will reliably work is building your own null-terminated string of null-terminated strings. -- Jim > I had said before that I had an array of byte arrays > working. I had that mixed up. What worked was > this: > > '-- using a string array instead of a null-delimited string. > > A1 = Split(sList, "|") > LNum = UBound(A1) + 1 > > '-- sList = Replace(sList, "|", Chr(0)) > '-- sList = sList & Chr(0) > > > ReDim AAsc(LNum) As String > For i2 = 0 To LNum - 1 > AAsc(i2) = A1(i2) > Next > AAsc(LNum) = vbNullChar > > '-- LRet = MakeCAB(sName, sDest, LNum, sList) > > '-- AAsc is an array declared as String and the MakeCAB last > '-- parameter is declared as Any in that case. I thought that was > "-- interesting: The C++ > '-- side is getting an array of c string pointers, which makes > '-- sense. But what surprises me is that it somehow receives > '-- a null-delimited string in the same way. Even though the former > '-- is an array of string pointers (pointer to pointer) while > '-- the latter is a pointer to a string, both have the exact same > result, '-- with array(0) getting through as a file path while > array(1) '-- gets through as the parent folder path. > > LRet = MakeCAB(sName, sDest, LNum, AAsc(0)) |