Click to See Complete Forum and Search --> : Please fill in the blanks (only 2)
Alan777
Mar 29th, 2002, 12:30 AM
New to C++. Please help me fill in the blanks which I have commented in the code below. I don't understand how to directly access char array arguments in a function.
(This is a Dll Export function to be called from VB)
The third parameter is a string which will be changed by the function. That is what I don't know how to do.
Apart from that, this code already works - I have tested it.
int _stdcall ShowOpenDlgAjP(HWND hOwner, char Filter[],/* this is where I need a buffer for the return path */ )
{
OPENFILENAME ofn;
int result;
memset(&ofn,0,sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hOwner;
ofn.lpstrFilter = Filter;
ofn.nFilterIndex = 1;
ofn.lpstrFile = "";
ofn.nMaxFile = 256;
ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
result = GetOpenFileName(&ofn);
//this is where I want to assign ofn.lpstrFile to the return buffer
return result;
}
MoMad
Mar 29th, 2002, 01:23 AM
First off, you are doing it all wrong.... But in C/C++ when you are assigning strings, you have to remember that they are an array of "char"s... so use a strcpy (string copy) function to copy the strings.., like this:
strcpy (Filter, ofn.lpstrFilter);
where the first parameter of the function is where you want the string to copied to, and the second, the string you want to copy from.
By the way, you need to #include <string.h>
Good luck.
Alan777
Mar 29th, 2002, 02:37 AM
MoMad thanks for your reply. The code actually works perfectly except I don't know how to change the value of the char array that I pass to the function. By the way, it is a dll export function to be called from VB. It works when I use this:
int _stdcall ShowOpenDlgAjP(HWND hOwner, char Filter[], char[255] Buffer)
But I know you can't change the value of the original Buffer string when using the by-value way. My question is just what do I change this parameter to so that I can get a return value.
In other words, how do I use a pointer to do it?
Thanks for the help.
:)
Zaei
Mar 29th, 2002, 10:36 AM
MoMad: The code WILL work, but only because Filter is already at some memory location. He is simply assigning that location to the Filter variable in the ofn structure, which will read the string correctly. Otherwise, he would have had to go and screw with new and delete, and such like.
Change both of your parameter types to char*. Then, at the last line, just add this line:
strcpy(Buffer, ofn.lpstrFile);
Make sure that your VB string is long enough to hold the buffer value though (Dim s As String * 256).
Z.
MoMad
Mar 29th, 2002, 11:45 AM
Zaei, you cannot do pointer arithmatics like that... most of the time it will work but its usually unsafe.
lpstrFilter is declared as char [256] and not a char *pointer...
most things compile just fine and sometimes even work as expected in c, but think of the worst case scenarios.
Im gald to help... by the way, instead of including the entirety of string.h, just use similar functions from a library that you are using for other purpose, say stdlib.h...
or make ur own:
char* strcopy( char* dest, const char* src )
{
char* buff = dest;
while (*buff++ = *src++);
*buff = 0;
return dest;
}
Thats all folks!
By the way stdlib.h has:
sprintf() which does the exact same as printf on a string!!
Zaei
Mar 29th, 2002, 11:51 AM
From MSDN:
lpstrFilter
Long pointer to a buffer that contains pairs of null-terminated
filter strings. The last string in the buffer must be terminated by
two NULL characters.
The first string in each pair is a display string that describes the
filter (for example, “Text Files”), and the second string specifies
the filter pattern (for example, “*.TXT”). To specify multiple filter
patterns for a single display string, use a semicolon to separate
the patterns (for example, “*.TXT;*.DOC;*.BAK”). A pattern string
can be a combination of valid file name characters and the
asterisk (*) wildcard character. Do not include spaces in the
pattern string.
The system does not change the order of the filters. It displays
them in the File Types combo box in the order specified in
lpstrFilter.
If lpstrFilter is NULL, the dialog box does not display any filters.
It IS a pointer, and you CAN do pointer arithmetic that way =). That is the reason that pointers are so good.
Z.
MoMad
Mar 29th, 2002, 12:04 PM
Very cool!!
but did you have to put it in a CODE section? it makes the page so big..
You are right Zaei, Pointers are the best!! Thats why C/C++ OWNZZ you all!!!!!!!!!
mwahahahahhhahahahhahhahahahhaha
<laughs frantically>...
Regards,
MoMad
Zaei
Mar 29th, 2002, 01:12 PM
Better =).
Z.
Alan777
Mar 31st, 2002, 04:38 AM
Thanks for the replies guys.
After much testing I have found the 1 and only line which is failing
in the function: strcpy(str, ofn.lpstrFile); (in red below)
The strange thing is, this line only fails when calling the function from VB. If I call the same function from C++ it works perfectly.
I have found that strcpy only fails if using ofn.lpstrFile
If I assign a string in quotes or a char[] it works fine and returns the string to VB. What's the deal? Do I need to convert the ofn.lpstrFile first or what? If so, how?
How do you convert from LPSTR to char[260] ?
int _stdcall ShowOpenDlgAjP(HWND hOwner, char Filter[], char str[260])
{
OPENFILENAME ofn;
int result = 0;
memset(&ofn,0,sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hOwner;
ofn.lpstrFilter = Filter;
ofn.nFilterIndex = 1;
ofn.lpstrFile = 0;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
result = GetOpenFileName(&ofn);
strcpy(str, ofn.lpstrFile);
return result;
}
By the way, I did try this:
Change both of your parameter types to char*.
and that failed big time.
I got an opinion from an experienced C++ programmer and he said the above is the correct way to do it. But he could not explain why it fails when calling from VB. (He does not use VB)
MoMad
Mar 31st, 2002, 05:46 PM
DOnt do str[260] just pass str[] like that.
Also you have to know that VB doesnt pass string arguments with array notation, it just doesnt... it passes char* by value but not by reference... if you want to modify a vb string pass it like this:
int _stdcall ShowOpenDlgAjP(HWND hOwner, LPSTR Filter, LPSTR* str);
and in VB:
ShowOpenDlgAjP(hOwner as long, byval Filter as string, byref str as string)
That should fix your little problem!
.. oh and your strcpy line should be changed to:
strcpy(*str, ofn.lpstrFile);
... also make sure you reserve space in VB BEFORE passing in the string parameter like:
Dim str as string
str = Space(260)
ShowOpenDlgAjP(me.hwnd, "somefilter", str)
And that should end your misserable problems... by the way, if it doesnt work in the IDE make an EXE and try it... the IDE has some sort of a bug that prevents you to run functions from dll's!
Zaei
Mar 31st, 2002, 10:09 PM
You can also define your string in VB as:
Dim St As String * 256 ' where 256 is the length of string you want.
Z.
MoMad
Mar 31st, 2002, 11:57 PM
Yup, thats right!!
Alan777
Apr 1st, 2002, 03:56 AM
Ok MoMad, I just tried both things you said above and neither of them work. Same problem. Memory can't be 'read' error.
Also, in all the APIs I can think of where you pass a string to be modified by the function, it is always passed ByVal.
That is what I want to do with my code. And as I said, the code I already have works just fine from C++. Also, I have already successfully modified VB strings using this method in testing.
As I said above. It ONLY fails when assigning from the OPENFILENAME structure. Or probably any struct. (haven't tried others yet)
Is it possible that you could try to run this code and see for yourself what's going on? I'd really appreciate it. Once I know the answer for this, I can carry on and apply it to many other functions without all these questions.
I'd use MSDN, but the MSDN documentation assumes a full working knowledge of C++ before you start - kind of defeating the purpose of the whole thing. :rolleyes:
BTW guys, my question has nothing to do with lpstrFilter.
There is no issue there.
Alan777
Apr 2nd, 2002, 12:35 AM
I've got the answer now. Thanks for your help guys. You were a big help in getting the final answer.
Final code:
int _stdcall ShowOpenDlgAjP(HWND hOwner, char Filter[], char str[])
{
OPENFILENAME ofn;
int result = 0;
unsigned int ctr = 0;
unsigned int max;
max = strlen(Filter);
// also added this to make it easier to send the filter
//replace | with null
for (ctr = 0; ctr < max; ctr++)
{
if (Filter[ctr] == 124) // ascii 124 = "|"
Filter[ctr] = 0;
}
memset(&ofn,0,sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hOwner;
ofn.lpstrFilter = Filter;
ofn.nFilterIndex = 1;
ofn.lpstrFile = str;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
result = GetOpenFileName(&ofn);
strcpy(str, ofn.lpstrFile);
return result;
}
MoMad
Apr 2nd, 2002, 11:00 AM
btw: you could just write '|' instead of 128. single quoting a char will return its ASCII value.
and you dont have to get the length of the string with strlen, just put in the middle term of your loop: Filter[i] != '\0'
AND, if you already assigned lpstrFile to str:
...
ofn.lpstrFile = str;
Then you dont have to do a strcpy at the end. So infact, you do not need the library string.h at all!
Alan777
Apr 7th, 2002, 04:14 AM
Originally posted by MoMad
AND, if you already assigned lpstrFile to str:
...
ofn.lpstrFile = str;
Then you dont have to do a strcpy at the end. So infact, you do not need the library string.h at all!
Yes I do. That's for the return value! :) (ie. the whole point of the function)
The assignment of str at the beginning is for a default file name if required.
Thanks for the other tips though :)
MoMad
Apr 7th, 2002, 10:53 PM
Wait, I just realized something...
the default value for the filename of the dialog box is 'str', which is also the name of the file the user chooses. Then why dont you just do something like:
return ofn.lpstr or NULL instead of the error code? wouldnt that save you an extra parameter? hehe.. but I know why you would need such a thing, error codes are better as return values than the actual retval.
So from your code, i see that you are making something in c (perhaps in dll) that pops up the browse for folder or file dialog... so whats next? how about checking for 'cancel' button etc... :)
hey have fun with that and post here if you find something interesting/boring/funny/hedious, etc.. and also if you wanna share some thoughts etc..
I was trying to do a search-in-file-and-replace function that is supposed to be fast... and also use regular expressions (but that could be step 2 or 3 or 4 or ...) anyways, the point being vb is too slow so i need c++ dll, and then its very hard to get much info on c++ stuff these days, especially on win32 stuff and all their c++ side-effects. anyways, so far i got it to 'search and find', (the replace will come soon) and also the speed bonuses and optimizations... so if anyone wants to learn something from these, just say something... or i might even throw together a tutorial on how its all done. (Note, i am extremely busy and might not be seen back here in vbforums for a long time, but i will eventually be back, so thanks in advance for all your patience and all your impatience, etc. etc. etc...); I am taking 5 college classes (including Calculus II and Physics III, the rest are programming related)
thanks,
MoMad
vbforums.com
Copyright Internet.com Inc., All Rights Reserved.