|
-
Jun 16th, 2004, 08:32 PM
#1
Thread Starter
Fanatic Member
cpp DLL returns garbage to VB
PHP Code:
#include <windows.h>
#include <string>
#include <vector>
using namespace std;
char * __stdcall enumerateFiles ( char * startPath, char * searchPattern) {
string directoryName;
string fileName ;
string temporary;
string returnValue;
vector<string> directoryNames;
int numberDirectories = 0;
int cont = 0;
HANDLE hFind;
WIN32_FIND_DATA wfd;
cont = 1;
temporary = startPath;
temporary += "*";
hFind = FindFirstFile(temporary.c_str(), &wfd);
if (hFind != INVALID_HANDLE_VALUE) {
while ( cont ) {
directoryName = wfd.cFileName;
if ( (directoryName != ".") && ( directoryName != "..") ) {
temporary = startPath;
temporary += directoryName;
if ( GetFileAttributes(temporary.c_str()) && FILE_ATTRIBUTE_DIRECTORY ) {
directoryNames.push_back (directoryName);
numberDirectories++;
}
}
cont = FindNextFile(hFind, &wfd);
}
cont = FindClose(hFind);
}
temporary = startPath;
temporary += searchPattern;
hFind = FindFirstFile(temporary.c_str(), &wfd);
cont = 1;
if ( hFind != INVALID_HANDLE_VALUE ) {
while ( cont ) {
fileName = wfd.cFileName;
if ( (fileName != ".") && (fileName != "..") ) {
temporary = startPath;
temporary += fileName;
returnValue = returnValue + temporary + ';';
}
cont = FindNextFile(hFind, &wfd);
}
cont = FindClose(hFind);
}
if (numberDirectories > 0) {
for ( int i = 0; i < numberDirectories; i++ ) {
temporary = startPath;
temporary = temporary + directoryNames[i] + "\\";
enumerateFiles( (CHAR * )temporary.c_str(), searchPattern);
}
}
return (CHAR *)returnValue.c_str();
}
Alot to look at but it works, anyway, this works fine when I use cout to display the data as it comes in, but when it comes to telling VB whats up it returns mostly those Y's with the accent over it. I think it has something to do with the fact I am using string class, but I don't know, maybe someone else has some more insight as to what im doing wrong.
-
Jun 16th, 2004, 10:23 PM
#2
you can't return a pointer from a function like that; as soon as that function ends, your std::string's destructor will be called and the pointer you returned will point to deleted memory. you should have the function accept a pointer to a buffer to copy the data into, ie:
Code:
void __stdcall enumerateFiles ( char * startPath, char * searchPattern, char * szBuffer, int size_of_buffer)
{
// ... may also want to check if buffer is too small.
strncpy(szBuffer, returnValue.c_str(), size_of_buffer);
}
Every passing hour brings the Solar System forty-three thousand miles closer to Globular Cluster M13 in Hercules -- and still there are some misfits who insist that there is no such thing as progress.
-
Jun 17th, 2004, 03:22 PM
#3
Thread Starter
Fanatic Member
Code:
strcpy(szBuffer, returnValue.c_str());
Well I added that in as so and didn't bother with the buffer size since it will change alot based on what directory im searching. Now dll compiles fine, but when I try to use it in VB such as:
VB Code:
Private Declare Sub enumerateFiles Lib "c:\recursiveSearch.dll" (ByVal startPath As String, ByVal searchPattern _
As String, ByRef szBuffer As String, ByVal bufferSize As Long)
Private Sub Command1_Click()
Dim strbuffer As String
enumerateFiles "d:\\", "*.mp3", strbuffer, 1000
End Sub
that, it just crashes VB to the desktop. I also tried with VarPtr around strbuffer, same thing happened. No clue why, hopefully you know and it just has something to do with how I implemented your solution.
-
Jun 17th, 2004, 04:54 PM
#4
Try ByVal for the last parameter too. If it doesn't work, things get complicated.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 17th, 2004, 06:28 PM
#5
Thread Starter
Fanatic Member
Code:
strcpy(szBuffer, returnValue.c_str());
That is what im using now finally, but when I use what i posted earlier, in VB with the VarPtr(szBuffer), I get the following error:
The instruction at 0x0faac7cb referenced memory at 0x6920736d, memory couldn't be read.
-
Jun 17th, 2004, 10:03 PM
#6
Try the other suggestion CornedBee offered, if you didn't already. IIRC in VB a String is already (under the hood) a pointer, so you don't need to pass it ByRef -- try just passing it ByVal and leaving out the VarPtr.
Every passing hour brings the Solar System forty-three thousand miles closer to Globular Cluster M13 in Hercules -- and still there are some misfits who insist that there is no such thing as progress.
-
Jun 17th, 2004, 10:32 PM
#7
Thread Starter
Fanatic Member
PHP Code:
#include <windows.h>
#include <string>
#include <vector>
using namespace std;
void __stdcall enumerateFiles ( char * startPath, char * searchPattern, char * szBuffer) {
string directoryName;
string fileName ;
string temporary;
string returnValue;
vector<string> directoryNames;
int numberDirectories = 0;
int cont = 0;
temporary = startPath;
HANDLE hFind;
WIN32_FIND_DATA wfd;
cont = 1;
temporary += "*";
hFind = FindFirstFile(temporary.c_str(), &wfd);
if (hFind != INVALID_HANDLE_VALUE) {
while ( cont ) {
directoryName = wfd.cFileName;
if ( (directoryName != ".") && ( directoryName != "..") ) {
temporary = startPath;
temporary += directoryName;
if ( GetFileAttributes(temporary.c_str()) && FILE_ATTRIBUTE_DIRECTORY ) {
directoryNames.push_back (directoryName);
numberDirectories++;
}
}
cont = FindNextFile(hFind, &wfd);
}
cont = FindClose(hFind);
}
temporary = startPath;
temporary += searchPattern;
hFind = FindFirstFile(temporary.c_str(), &wfd);
cont = 1;
if ( hFind != INVALID_HANDLE_VALUE ) {
while ( cont ) {
fileName = wfd.cFileName;
if ( (fileName != ".") && (fileName != "..") ) {
temporary = startPath;
temporary += fileName;
returnValue = returnValue + temporary + ';';
}
cont = FindNextFile(hFind, &wfd);
}
cont = FindClose(hFind);
}
if (numberDirectories > 0) {
for ( int i = 0; i < numberDirectories; i++ ) {
temporary = startPath;
temporary = temporary + directoryNames[i] + "\\";
enumerateFiles( (CHAR * )temporary.c_str(), searchPattern, szBuffer);
}
}
strcpy(szBuffer, returnValue.c_str());
}
VB Code:
Private Declare Sub enumerateFiles Lib "c:\recursiveSearch.dll" (ByVal startPath As String, _
ByVal searchPattern As String, _
ByVal szBuffer As String)
Private Sub Command1_Click()
Dim strbuffer As String
enumerateFiles "d:\\", "*.mp3", strbuffer
MsgBox strbuffer
End Sub
error:
0xBlah referenced memory at 0x00000000. Memory couldn't be written.
Does that have something to do with the szBuffer pointer not being initialized or something? Im passing it a variable as you can see in the VB code, no clue what the heck is going on at this point.
-
Jun 17th, 2004, 10:47 PM
#8
try something like this:
VB Code:
Private Declare Sub enumerateFiles Lib "c:\recursiveSearch.dll" (ByVal startPath As String, _
ByVal searchPattern As String, _
ByVal szBuffer As String)
Private Sub Command1_Click()
' create strbuffer with size of 512
Dim strbuffer As String * 512
enumerateFiles "d:\\", "*.mp3", strbuffer
MsgBox strbuffer
End Sub
the error is probably stemming from the fact that strbuffer was empty.
Every passing hour brings the Solar System forty-three thousand miles closer to Globular Cluster M13 in Hercules -- and still there are some misfits who insist that there is no such thing as progress.
-
Jun 18th, 2004, 01:25 AM
#9
Thread Starter
Fanatic Member
Alright well new post cause this different topic than the old one before it, but I tried clocking the speed on the dll and it is actually slower than VB with that exact function. Does it have to do with the fact I am using the string class so heavily?
-
Jun 18th, 2004, 03:01 AM
#10
No, probably because a conversion is done between VB's internal character representation and the one you use in C++.
There are ways to make it faster, these involve BSTR.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 18th, 2004, 05:36 AM
#11
Ok. You see, VB's internal strings are BSTRs. Those are length-counted nul-terminated unicode strings.
By declaring your function like this:
Code:
void __stdcall enumerateFiles ( BSTR * startPath, BSTR * searchPattern, BSTR * szBuffer) {
and making all VB parameters ByRef, you should be able to avoid the conversion and directly manipulate the wide character strings. However, keep in mind that you need to keep the integrity of the BSTR and follow all UNICODE rules of C++ and the WinAPI.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 18th, 2004, 05:42 AM
#12
Thread Starter
Fanatic Member
Alright trying to conver it over now, I got 8 of the same error.
EDIT: Am I able to typecast these when trying to asssign/concatenate to a std string?
Last edited by dsheller; Jun 18th, 2004 at 11:35 AM.
-
Jun 18th, 2004, 05:44 AM
#13
No. See, you should really look up info about unicode, wide characters and C++ before attempting to do this.
For one, you need std::wstring now.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 18th, 2004, 06:10 AM
#14
Thread Starter
Fanatic Member
Alright well I have come down to a few conclusions, all my strings I am using must be wstring, I am not allowed to typecast, and I am going to have to use a whole new set of functions to manipulate these strings, am I write on most counts or should I keep reading?
-
Jun 18th, 2004, 06:13 AM
#15
Pretty much, yeah. Basically, you must postfix all WinAPI functions with W. Note that this destroys Win9x compatibility.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 18th, 2004, 06:18 AM
#16
Thread Starter
Fanatic Member
How about lazyman operators such as "=, +=..." those don't seem to be liked too much either.
-
Jun 18th, 2004, 06:23 AM
#17
They should work just fine with wstrings and wstring+wchar_t * and wstring+L"literal".
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 18th, 2004, 06:24 AM
#18
Thread Starter
Fanatic Member
temporary = startPath;
I assume it doesn't work with BSTR's?
-
Jun 18th, 2004, 06:34 AM
#19
It works with BSTR, but not with BSTR*.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 18th, 2004, 06:44 AM
#20
Thread Starter
Fanatic Member
I've noticed google doesn't have much information on wstring, I've looked for examples of how to use the functions and can't find any, so far still looking for an example of compare.
-
Jun 18th, 2004, 06:53 AM
#21
wstring is used exactly the same way as string. They're both instantiations of the same template, basic_string.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 18th, 2004, 07:02 AM
#22
Thread Starter
Fanatic Member
Hmm... well I keep trying to use it as I would with string class like this:
Code:
if ( temporary != "." ) {
...
}
But fail at every attempt, I know you are probably frustated with all these questions but I am having alot of trouble using this.
Alright got past that pretty cheap like, just made a wstring that was equal to the string literals and compared those instead. Now I am down to two errors and have no clue what to do without typecasting, I have to do two things ill paste the lines:
Code:
enumerateFiles(temporary , searchPattern, szBuffer);
szBuffer = returnValue.c_str();
enumerateFiles( BSTR, BSTR, BSTR), but temporary is a wstring.
szBuffer is a BSTR, and returnValue... a wstring. I know I have to convert them somehow but I haven't a clue!
Last edited by dsheller; Jun 18th, 2004 at 07:27 AM.
-
Jun 18th, 2004, 08:09 AM
#23
Thread Starter
Fanatic Member
Alright, I read and found I should use the atlconv.h library, so I am I am using W2BSTR() function and I get an error which pertains to the atlconv library...
c:\program files\microsoft visual studio\vc98\atl\include\atlconv.h(48) : error C2065: '_ASSERTE' : undeclared identifier
Do I have to download a new version of this file?
-
Jun 18th, 2004, 10:09 AM
#24
I have no idea what _ASSERTE is, but ATL is a big library that you probably don't want to be stuck with, certainly not for the sake of this little macro.
Now. wstring uses wide characters and literals that are assigned to or compared with wstrings must therefore be wide characters too. To get a wide character literal you prefix it L:
L"This is a wide literal."
The return copy is more complicated. You can either copy the value in, or you can replace the BSTR object with one you created with SysAllocString. But that means you need to free the old one with SysFreeString.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 18th, 2004, 10:14 AM
#25
Thread Starter
Fanatic Member
What bout WideCharToMultiByte, or something to that effect, not sure on its exact name. Would that be a possible solution?
-
Jun 18th, 2004, 10:19 AM
#26
No. Conversion between wide and narrow chars is exactly what you want to avoid, it takes too long.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 18th, 2004, 10:22 AM
#27
Thread Starter
Fanatic Member
Ok, I think I follow you on the return value code, I am trying something like this:
Code:
SysFreeString(szBuffer);
BSTR temp;
temp = SysAllocString(returnValue.c_str());
szBuffer = temp;
As for passing the function the BSTR that it wants when all I have is the wstring, I am still at a loss.
-
Jun 18th, 2004, 10:40 AM
#28
Alright, this is a very rough translation with lots of bugs likely, but it should give you the idea.
Code:
void __stdcall enumerateFiles ( BSTR * startPath, BSTR * searchPattern, BSTR * szBuffer) {
if(*szBuffer) {
SysFreeString(*szBuffer);
}
wstring ret;
innerEnumFiles(*startPath, *searchPattern, ret);
*szBuffer = SysAllocString(ret.c_str());
}
void innerEnumFiles(const wchar_t *startPath, const wchar_t *searchPattern, wstring &ret) {
wstring directoryName;
wstring fileName;
wstring temporary;
wstring returnValue;
vector<wstring> directoryNames;
int numberDirectories = 0;
int cont = 0;
temporary = startPath;
HANDLE hFind;
WIN32_FIND_DATAW wfd;
cont = 1;
temporary += L"*";
hFind = FindFirstFileW(temporary.c_str(), &wfd);
if (hFind != INVALID_HANDLE_VALUE) {
while ( cont ) {
directoryName = wfd.cFileName;
if ( (directoryName != L".") && ( directoryName != L"..") ) {
temporary = startPath;
temporary += directoryName;
if ( GetFileAttributesW(temporary.c_str()) && FILE_ATTRIBUTE_DIRECTORY ) {
directoryNames.push_back(directoryName);
numberDirectories++;
}
}
cont = FindNextFileW(hFind, &wfd);
}
cont = FindClose(hFind);
}
temporary = startPath;
temporary += searchPattern;
hFind = FindFirstFile(temporary.c_str(), &wfd);
cont = 1;
if ( hFind != INVALID_HANDLE_VALUE ) {
while ( cont ) {
fileName = wfd.cFileName;
if ( (fileName != L".") && (fileName != L"..") ) {
temporary = startPath;
temporary += fileName;
ret += temporary + L';';
}
cont = FindNextFileW(hFind, &wfd);
}
cont = FindClose(hFind);
}
if (numberDirectories > 0) {
for ( int i = 0; i < numberDirectories; i++ ) {
temporary = startPath;
temporary = temporary + directoryNames[i] + L"\\";
innerEnumFiles(temporary.c_str(), searchPattern, ret);
}
}
}
VB Code:
Private Declare Sub enumerateFiles Lib "c:\recursiveSearch.dll" (ByRef startPath As String, _
ByRef searchPattern As String, _
ByRef szBuffer As String)
Private Sub Command1_Click()
Dim strbuffer As String
enumerateFiles "d:\\", "*.mp3", strbuffer
MsgBox strbuffer
End Sub
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 18th, 2004, 11:05 AM
#29
Thread Starter
Fanatic Member
Ok, well I have it returning a value when its in a stand alone program, but DLL just doesnt work.
Cleaned up most of the useless posts.
Last edited by dsheller; Jun 18th, 2004 at 11:36 AM.
-
Jun 18th, 2004, 11:25 AM
#30
You can delete your posts by going to edit, checking the delete checkbox at the top and then hitting the delete button.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 18th, 2004, 03:38 PM
#31
Thread Starter
Fanatic Member
How on earth do I debug this DLL, I haven't a clue as to where to start, I tried making it write to file, that didn't work out too well =/
-
Jun 18th, 2004, 03:40 PM
#32
Why not?
I once managed to hop with the debugger from VB to VC++, can't remember how though.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 19th, 2004, 05:41 AM
#33
Thread Starter
Fanatic Member
Alright well just by posting messageboxes throughout the various structures I have found that it doesn't get past this part:
Code:
wstring directoryName;
wstring fileName;
wstring temporary;
wstring returnValue;
vector<wstring> directoryNames;
int numberDirectories = 0;
int cont = 0;
temporary = *startPath;
HANDLE hFind;
WIN32_FIND_DATAW wfd;
cont = 1;
temporary += L"*";
hFind = FindFirstFileW(temporary.c_str(), &wfd);
MessageBox(FindWindow(NULL, "Debug"), "FindFirstFile", "NULL", 1);
That is the first and last messagebox given to me.
So I think it has something to do with the API call but I don't know hwo to find out what temporary is equal too... it should work, works in a console.
-
Jun 19th, 2004, 01:34 PM
#34
Well, but where is the next message box and does it actually crash?
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 19th, 2004, 02:13 PM
#35
Thread Starter
Fanatic Member
It doesnt crash, it just returns nothing =/ next box comes inside the first if structure "if (hFind != INVALID_HANDLE_VALUE) {"
-
Jun 19th, 2004, 02:19 PM
#36
Well, let the message box tell you then.
MessageBoxW(0, L"Title", temporary.c_str(), 0);
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 19th, 2004, 02:33 PM
#37
Thread Starter
Fanatic Member
That outputs gibberish, like little boxes and other extended ascii codes. The messagebox does that is, where it should be displaying the temporary.c_str() is the problem, the title part works just fine =/
EDIT:
Puts out same gibberish everytime I run the VB part.
Last edited by dsheller; Jun 19th, 2004 at 02:36 PM.
-
Jun 19th, 2004, 02:37 PM
#38
What about
MessageBoxW(0, L"Title", startPath, 0);
And how did the *startPath get back in there?
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jun 19th, 2004, 02:40 PM
#39
Thread Starter
Fanatic Member
startPath is 2 little boxes =)
As for how it got in there... um... ? It's from the code you gave me where its being passed from the main function.
-
Jun 19th, 2004, 02:47 PM
#40
Ok, place a message box in the outer function (the __stdcall one) and tell me the values there. *startPath and *searchPattern.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|