|
To find out where you are, GNU Fortran has a GETCWD call
link[^] I don't know how standard it is.
It doesn't seem to have a corresponding SETCWD call.
If you are starting the program using CreateProcess() then you can set the working directory, and I think it will default to the working directory of the calling process if you don't.
Peter
"Until the invention of the computer, the machine gun was the device that enabled humans to make the most mistakes in the smallest amount of time."
|
|
|
|
|
Unfortunately the Absoft compiler is a bit basic and does not have such luxuries. But I must check what I put in CreateProcess. I have to put it all in the command line, maybe I missed the path and it was just luck that it ran where it is.
-------------
Bibo ergo sum
|
|
|
|
|
Check out the lpCurrentDirectory parameter to the CreateProcess call
Peter
"Until the invention of the computer, the machine gun was the device that enabled humans to make the most mistakes in the smallest amount of time."
|
|
|
|
|
Hi,
if pathname length is a concern, you can always "map a network drive" (it works on the local machine too, despite the name), i.e. assign a drive letter to a (deep) subdirectory, allowing you to shorten the pathname considerably.
|
|
|
|
|
Fixed it!
I finally ported the old Fortran to Windows and recompiled it. I put some prints in to see what it gets up to.
It works. The problem was the Fortran having been compiled under Cygwin, some kind of Linux for Windows. It ran under Windows, but not quite. So when I compiled it myself, it could use the strings to open the file.
Just because it runs from the command line does not mean you can embed it and it still runs.
|
|
|
|
|
Hello
I have a MFC program with 2 threads. First is User Interface (Main) thread, and second one is worker thread that is created in the beginning and used till the end of application life. In the second thread in the begining I create CInternetSession and CHTTPConnection. I make some HTTP requests from second thread and everything is fine. But this is until I create and show InternetExplorer control in UserInterfece thread. Then something goes wrong and i lost my cookies in second thread and after a few requests my application crash (I will find where in code exactly this happened) When I show Internet Explorer control my second thread didn't make are requests. But I think that the problem is related with multithread using of WinInet libraries.
I found this problem soon because it didn't happened on computers that have all windows updates (Windows XP)
What you will recommend me to do?
P.S. I forget to mention that in second thread I make mostly a HTTPS requests
P.S. IE Control that I use is this one
http://www.codeproject.com/KB/miscctrl/simplebrowserformfc.aspx[^]
Julian Popov
абвгдежзийклмнопрстуфхцчшщъьюя
modified on Tuesday, December 9, 2008 6:04 AM
|
|
|
|
|
For one of my projects I've created a class wrapper around some functions contained in a DLL. To use these DLL functions, I instantiate an object of the type class wrapper, and then call the member function LoadDLL(). LoadDLL() calls ::LoadLibrary() for the DLL, and then calls GetProcAddress() for each DLL function I wish to wrap. If any of the functions couldn't be found, I wish to FreeLibrary(), and return false.
At the moment I do something along the lines of:
typedef void (*p2DLLFunc1) (void);
typedef char* (*p2DLLFunc2) (void);
bool CDLLWrapper::LoadDLL()
{
bool bResult = false;
m_hmoduleDll = ::LoadLibrary(_T("DLLName"));
if (NULL != m_hmoduleDll)
{
m_funcDLLFunc1 = reinterpret_cast<p2DLLFunc1>(GetProcAddress(m_hmoduleDll, _T("DLLFunc1")));
m_funcDLLFunc2 = reinterpret_cast<p2DLLFunc2>(GetProcAddress(m_hmoduleDll, _T("DLLFunc2")));
m_funcDLLFunc3 = reinterpret_cast<p2DLLFunc1>(GetProcAddress(m_hmoduleDll, _T("DLLFunc3")));
if ( NULL != m_funcDLLFunc1 &&
NULL != m_funcDLLFunc2 &&
NULL != m_funcDLLFunc3)
{
bResult = true;
}
else
{
::FreeLibrary(m_hmoduleDll);
}
}
return bResult;
}
However, when lots of functions are being wrapped the above method is a bit tedious and can be error prone. Instead, I would like to do it with a lookup table, like so
bool CDLLWrapper::LoadDLL()
{
struct MyLUT {
TCHAR* tcFuncName;
funcDLLFunc;
int iFunctionSignatureType;
};
static MyLUT arrWrappedFuncs[] = { _T("DLLFunc1"), m_funcDLLFunc1, 0
_T("DLLFunc2"), m_funcDLLFunc2, 1
_T("DLLFunc3"), m_funcDLLFunc3, 0
};
const int iNUM_WRAPPED_FUNCTIONS = sizeof(arrWrappedFuncs) / sizeof(MyLUT);
bool bResult = false;
m_hmoduleDll = ::LoadLibrary(_T("DLLName"));
if (NULL != m_hmoduleDll)
{
bResult = true;
for (int i = 0; i < iNUM_WRAPPED_FUNCTIONS; ++i)
{
switch(arrWrappedFuncs[i].iFunctionSignatureType)
{
case 0:
{
arrWrappedFuncs[i].funcDLLFunc = reinterpret_cast<p2DLLFunc1>(GetProcAddress(m_hmoduleDll, arrWrappedFuncs[i].tcFuncName));
}
break;
case 1:
{
arrWrappedFuncs[i].funcDLLFunc = reinterpret_cast<p2DLLFunc2>(GetProcAddress(m_hmoduleDll, arrWrappedFuncs[i].tcFuncName));
}
break;
default:
{
}
}
if (NULL == arrWrappedFuncs[i].funcDLLFunc)
{
bResult = false;
break;
}
}
if (!bResult)
{
::FreeLibrary(m_hmoduleDll);
}
}
return bResult;
}
The two problems I've got are:
1) How can I store a type in an array, so that I can use it in the reinterpret_cast<> ?
2) What type to define funcDLLFunc in struct MyLUT ?
Not sure about (1), but was thinking of using a union for (2), containing all the different function signatures. Every time a newly wrapped function had a different signature, I would just add a new member to the union and create a new Type.
If it's not possible to store a type in an array, then I guess the only solution is to have a switch statement on iFunctionSignatureType, and then just have the GetProcAddress() line for each type with a different reinterpret_cast<>. However, this is tedious as well, hence my hope for being able to store a type in an array.
Any ideas ?
|
|
|
|
|
Whz do you need reinterpret_cast at the first place? Shouldn't that work without any casting?
> The problem with computers is that they do what you tell them to do and not what you want them to do. <
|
|
|
|
|
Unfortunately not, as you get a compiler error:
error C2440: '=' : cannot convert from 'FARPROC' to 'p2DLLFunc1'
|
|
|
|
|
Try something like:
struct MyLUT {
TCHAR* tcFuncName;
FARPROC *funcDLLFunc;
};
static MyLUT arrWrappedFuncs[] = { {_T("DLLFunc1"), (FARPROC *)&m_funcDLLFunc1},
{_T("DLLFunc2"), (FARPROC *)&m_funcDLLFunc2},
{_T("DLLFunc3"), (FARPROC *)&m_funcDLLFunc3},
};
...
(*arrWrappedFuncs[i].funcDLLFunc) = GetProcAddress(m_hmoduleDll, arrWrappedFuncs[i].tcFuncName));
...
I just modified your code, so it might not compile, and probably needs adjustment here and there but maybe you get the main idea.
> The problem with computers is that they do what you tell them to do and not what you want them to do. <
|
|
|
|
|
FARPROC is defined as a function pointer to a function that receives no input, and returns an int (ie. int func(void)). Therefore, this cannot be used for functions whose parameter list and return type are different (eg. char* func1(int)).
|
|
|
|
|
A pointer in itself is just a memory address, what parameters how are passed upon a call is decided where and when you call the function thorough the pointer, but correct me if i am wrong. Just try this:
void *P1 = (void *)GetProcAddress(DLLHande, "proc_name");
FARPROC P2 = GetProcAddress(DLLHande, "proc_name");
pDLLFunc1 P3 = (pDLLFunc1)GetProcAddress(DLLHande, "proc_name");
pDLLFunc1 P4 = reinterpret_cast<pdllfunc1>(GetProcAddress(DLLHande, "proc_name"));
</pdllfunc1>
And check out the 4 pointer values (for example in the watch window of your debugger if you are using Visual Studio), they all should be the same,
> The problem with computers is that they do what you tell them to do and not what you want them to do. <
|
|
|
|
|
You are correct, and that is the problem. If I don't cast it to the correct type when calling GetProcAddress(), I will have to cast it later on when I call the function pointed to by the pointer. Either way, I will need to cast it at some point. Otherwise I don't think it will let me call it with the relevant parameters and return type.
I will have to do some testing to be sure, but my current understanding makes me think it won't work.
|
|
|
|
|
How about a different aproach, use a template class, something like this:
class CConverterBase
{
public:
virtual operator void =(const FARPROC ptr) = 0;
};
template<typename tfuncptr="">
class CConverter: public CConverterBase
{
TFuncPtr &fFuncPtrPtr;
public:
CConverter(TFuncPtr &ptr):fFuncPtrPtr(ptr) {}
operator void =(const FARPROC ptr)
{
fFuncPtrPtr = (TFuncPtr)ptr;
return fFuncPtrPtr;
}
}
</typename>
And then something like:
class Func
{
TCHAR *pszName;
CConverterBase *ptr;
};
...
Func FuncArr[] = {{_T"DLLFunc1", new CConverter(m_DLLFunc1)}, {_T"DLLFunc2", new CConverter(m_DLLFunc2)}, ...};
...
(*FuncAtt[I].ptr) = GetProcAddress(dllhandle, FuncAtt[I].pszName);
...
And of course don't forget to free up the objects you instantiated.
> The problem with computers is that they do what you tell them to do and not what you want them to do. <
|
|
|
|
|
I've been thinking a similar thing that I might have to use some C++ features to achieve what I'm after. The idea of a template class is good, but the FuncArr[] can only be initialized with static data (ie. known at compile time).
Hmmm, time to put my C++ hat on
|
|
|
|
|
Defenestration wrote: Any ideas ?
Have you read this article on dynamic linking?
"Love people and use things, not love things and use people." - Unknown
"The brick walls are there for a reason...to stop the people who don't want it badly enough." - Randy Pausch
|
|
|
|
|
You can use a MS extension in GetProcAddress() calls:
(FARPROC&) func_ptr = GetProcAddress ( hModule, "FunctionName" ); That way you don't have to make a new typedef for each function pointer.
|
|
|
|
|
I need to send data through a pipe to my main thread and block until the data is read, or until a new command is received from the main thread. It's very important for the write operation to be able to unblock if a new command is available.
There is sufficient light for those who desire to see, and there is sufficient darkness for those of a contrary disposition.
Blaise Pascal
|
|
|
|
|
Hy,
I am still having problem handling some data types and the data itself in memory and so on.
For example: For getting the text of an edit control (winapi) requires to create a buffer with enaugh space. I did (unicode) for example:
length is from the type of WORD in the example, but i used length as an integer.
TCHAR *buf = new TCHAR[length+1];
So now it says the FIRST WORD needs to have the length of the string in the edit field, which I retrieved before.
The example shows:
*((LPWORD)buf) = length;
However, when I use my way: *(buf) = length it ends in the same result.
So, my question is whats so special in the way how msdn do it?
-----
And then, did i understand the line right ? Here is my explanation:
In memory we have allocated space for the variable buf. The length is the length of TCHAR * mylength(the variable)
But in memory it is handled as "we need xx bytes" right?
Then *(buf) points to the first byte (in array it is index 0)
But because we need the first word, we convert the normal pointer (i think normal is a void pointer) to an pointer of a WORD. So now the index 0 for examples is exactly 1 WORD.
Then we write the length variable which is also a WORD to the location.
Is this right or do I misunderstand something?
----
And why is my way *(buf) = length also working?
I hope everybody understand whats my problem. Thank you for help.
bye,
gabbana
|
|
|
|
|
gabbana wrote: I hope everybody understand whats my problem. Thank you for help.
For instance I cannot understand your problem.
To get the text of an edit box, using Windows API , you may to call GetWindowText this way
TCHAR szBuf[0x100];
if (! GetWindowText(hWnd, szBuf, sizeof(szBuf)/sizeof(szBuf[0])))
{
}
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
*((LPWORD)buf) = length; - this will copy sizeof(WORD) bytes into the first sizeof(WORD) bytes of your buffer
*(buf) = length - this will convert your integer (length) to a TCHAR and put that into the first TCHAR pointed at by buf.
So let's assume WORD is 2 bytes and TCHAR is also 2 bytes (unicode), in this case the 2 versions should produce the same result, but if you compile wihout unicode, TCHAR being 1 byte then in the second case, only 1 bytes will be changed in your buffer while the 2nd byte is left unchanged, you would probably get a warning from your compiler too ('conversion from int to char, possible loss of data' or similar).
On a sidenote, could you show me where you read this:
gabbana wrote: So now it says the FIRST WORD needs to have the length of the string in the edit field, which I retrieved before.
please?
> The problem with computers is that they do what you tell them to do and not what you want them to do. <
|
|
|
|
|
Okay, now I think i found some information.
Lets start with Bits and Bytes:
A BIT can be 1 or 0. So we have 2 options
A BYTE contains 8 Bits. So we have 2^8 possible option (ASCII/ANSI) So we have all the 256 chars.
A WORD contains 16 Bits (2BYTE)
A WCHAR (wide char) contains also 16bits (2BYTE) -> chinese languag and so on need 2 Bytes for one char.
A Pointer (I said its normally a void point but that was wrong) is normally a pointer to a specific datatype, for example WCHAR *buf -> means we have a Pointer which points to ONE WCHAR somewhere in memory (as long as we allocate space)
So now we allocate space: *buf = new WCHAR[16]; This means we allocate 16 bits per char, so we have allocated 2*16 bytes = 32 bytes which means 2^32 bits.
So if we use the example with edit field, we get an integer (the length) and convert it to a WORD. BECAUSE the edit field must return something >0 we CAN convert it to an unsigned integer, a WORD right?
-> Now why do we need the following?
*((LPWORD)buf) = length
And why does
*(buf) = (WORD)length
also works ?
So we know that WCHAR contains 2Bytes. A WORD also contains 2Bytes.
So the point normaly shows to the firt wchar which is also a WORD in this example. So we can easily move the length to this location. Right ?
But why the first way ?
So it could be that if we does not using unicode, the pinte would only show to the first ONE byte in the memory. And then we need to convert it it first to an LPWORD to be sure the pointer shows to the FIRST 2Bytes, a WORD in memory. And so it works.
I hope its not too long and someone can confirm my explanation.
Thank you very much.
bye,
gabbana
|
|
|
|
|
Oh I see the first two answers now. Thank you very much but it would be great if you also confirm what I say in the last post. I think the unicode stuff I mentioned is right, juhuu.
|
|
|
|
|
As far as i can tell, you understood it quite well. Just to clear things up, a pointer alone always points at 1 byte in memory, giving it a type is, how to say, just a more clear, logical way of handling things. Hmm, hard to explain what i mean, i try to give an example:
WORD *WordPointer = (WORD *)malloc(sizeof(char));
So, althorough WordPointer is assumed to be pointing at a WORD being 2 bytes, it still points at the 1 allocated byte. So if then you do
*WordPointer = 3;
It will write 2 bytes in memory but we only allocated 1 byte, this can result in 2 (or maybe more) things:
-You get an access violation because you are trying to write a memory location (the second byte) that does not belong to your process. This is a better result because it is much easier to track down and correct.
-The second byte of the word actually belongs to your process but is part of something else, for example an integer's first byte you use somewhere else, then you owerwrite this changing your integer, this problem is much harder to track down and correct because it doesn't result in an error right away but maybe later when you try to use your integer and see that it has some bogous value and you have no idea where it came.
</smartass_mode>
I hope this is clear, don't want to lecture you, just thought this info might be useful for you.
> The problem with computers is that they do what you tell them to do and not what you want them to do. <
|
|
|
|
|
Ahh okay great. Thank you very much.
I think I will try a bit and see what the debugger shows to become a better "feeling" of how something of that happens so that I know "Aahh, I have an error with the memory allocation".
|
|
|
|
|