|
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".
|
|
|
|
|
I wanted to know what is difference between CreateThread & AfxBeginThread
while creating thread?
Thanks in advance
Nikesh
|
|
|
|
|
When you're using MFC for developing applications, you should use AfxBeginThread() due to internal things in the framework that need to be set up correctly.
::CreateThread() is the Platform SDK version version when building applications with C++ without MFC support.
At last a little hint, pasted from MSDN:
A thread that uses functions from the C run-time libraries should use the beginthread and endthread C run-time functions for thread management rather than CreateThread and ExitThread. Failure to do so results in small memory leaks when ExitThread is called.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Roger Stoltz wrote: should use the beginthread and endthread
You should use beginthreadex() as it gives you more control, and endthreadex() as endthread() is fundamentally flawed.
modified on Tuesday, December 9, 2008 4:45 AM
|
|
|
|
|
Defenestration wrote: You should use beginthreadex() as it gives you more control, and endthreadex() as endthread() is fundamentally flawed.
As I wrote, this was a quote from MSDN as a hint when using Kernel32.dll from other languages than C/C++ and a different calling convention is used.
Regarding the use of any of the functions for "ending" a thread, neither of them should be used. You should simply return from the thread controlling function and if that turns out to be a problem, the design should be corrected.
Regarding beginthreadex() , you may use it unless you're building an MFC application. The only correct option is to use AfxBeginThread() when building with MFC support. This is not a matter of opinion.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Roger Stoltz wrote: Regarding the use of any of the functions for "ending" a thread, neither of them should be used. You should simply return from the thread controlling function
Indeed, and the only bulletproof method for knowing when a thread has finished, is to Wait...() on the thread handle.
|
|
|
|
|
Hi All
i want to write log file in .csv file.I am useing this code
[code]
CString strLine;
TRY
{
CStdioFile file(_T("\\mytestfile.CSV"), CFile::modeWrite|CFile::modeCreate);
file.Seek(0,CFile::end);
file.WriteString(tim.Trim());
file.WriteString("\n");
file.Close();
}
CATCH(CFileException, e)
{
e->ReportError();
}
END_CATCH
[/code]
But when new values(tim.Trim()) is come then old values auto delete.But i want to store all valuse in .csv file.Plz help me
|
|
|
|
|
I am not sure I understood your problem but you call this code several times and only the last value is saved to your file. Is that your problem ? If yes, then you need to use the CFile::modeNoTruncate flag (see here[^]). But doing that you will never erase your file (so, each time values will be appended to your file). A better approach would be to open the file only once, write all your values then close the file.
|
|
|
|
|
MsmVc wrote: CStdioFile file(_T("\\mytestfile.CSV"), CFile::modeWrite|CFile::modeCreate);
add CFile::modeNoTruncate..
MsmVc wrote: file.Seek(0,CFile::end);
you can also use existing member function SeekToEnd
I hope it helps.
Regards,
Sandip.
|
|
|
|
|
Thanks SandipG.
Just i was forget to use CFile::modeNoTruncate.
|
|
|
|
|