|
Hi, I've got this problem when developing my first DLL:
I have a DLL with an Interface class. I also have an application that calls some functions from the Interface class.
In the application there exist a function that I want to be called from the DLL (as a callback), so I pass a function pointer to the DLL.
I want to store the function pointer inside the DLL so I can call the function whenever I want, for this reason I have created an struct in which I store the function pointer and some other things. Until here, everything fine...
The problem comes when doing an instance of the struct; if I do that instance inside the Interface class (as a member) I cannot copy the function pointer in it; but if I do the instance outside any class (that is as "global") then there is no problem when copying the functon pointer.
Does anybody knows why can this happen?, it can be a problem of memory access?
Here is a "meta-language" example:
DLL:
In Interface.h:
typedef struct
{
functionpointer
}MyStruct;
class Interface
{
Interface ();
MyStruct mystruct;
void FillStruct (function_pointer_from_outside); //this is the exported function
}
In Interface.cpp
void Interface::FillStruct(function_pointer_from_outside)
{
mystruct.functionpointer = function_pointer_from_outside; //THIS GIVES EXECUTION PROBLEM
}
On the other hand if I make something like this, it works:
In Interface.h:
typedef struct
{
functionpointer
}MyStruct;
class Interface
{
Interface ();
void FillStruct (function_pointer_from_outside);
}
In Interface.cpp
MyStruct mystruct; //Instance as "global"!!!!!
void Interface::FillStruct(function_pointer_from_outside)
{
mystruct.functionpointer = function_pointer_from_outside; //OK!!!
}
HELP!!
|
|
|
|
|
My first question would be, what is the error during execution ? A run-time error ? An exception ? An access violation ?
Finding out the error type is integral to determining what the cause of the error is. I believe it to be an access violation, though. As a suggestion, you should try defining the function pointer as a standard pointer-to-function type. You shouldn't encapsulate it into a struct (what is the reason behind this, by the way ?)
Another working way could be to call GetModuleHandle on the main application. This returns a handle to the executable used to start the process. In english, it is the starting address of your main application. Now, if you pass this module handle into the DLL, you can use GetProcAddress inside the DLL code to query for the address of the function in the main module. This is something of a reverse-usage of the most common case: querying for a function address inside a DLL. Instead, we query for a function address inside the main application.
The returned value can then be used to invoke the function in the main application module. Using GetProcAddress ensures that the memory location pointed to by the returned pointer is ensured to contain information of to what module's memory area it points to. This may not be the case if you just pass the pointer using address-of operator.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
It is an exception error; a windows called "Just-In-Time Debugging" appear saying:
"An exception 'System.NullReferenceException' has occurred in testUI.exe".
Here is the definition of the pointer in the application (testUI.exe); as you can see, it is a pointer to a member function:
typedef void (CListener::*ListPtr)();
ListPtr pListPtr = new ListPtr;
pListPtr = &CListener::MyFunction;
I use a struct in the DLL because I want to store the pointer to the function, the pointer to the CListener class created in the textUI.exe, and an integer that acts as an identifier. Furthermore, I want to create an array of this struct, because I want the DLL to be capable to work with more that one textUI.exe at the same time (each one of them has its own version of "MyFunction"), and I want to store independently a reference to every function of each CListener object of each textUI.exe.
Thanks for your help
Irene
|
|
|
|
|
Humm..
It seems here that each textUI.exe executable creates a new object of the CListener class ? Is this correct ?
So, could there be a reason why you wouldn't just pass around a pointer to the object itself ? Like, the executable that loads the DLL provides a function that will return the address of the local CListener object ? If the DLL is aware of the declaration of CListener , you can use the returned address as a standard pointer-to-class to call the member functions.
This way, you wouldn't need a pointer to the member function, but would have a pointer to the entire class. The pointer's size wouldn't change much, so the memory requirements would be held in check.
Naturally, this approach would place more strict design issues on the DLL code, especially if different functions of the class need to be called at different times. Perhaps you should increase the struct so that in addition to the pointer and the reference number, it would contain a flag that specifies the function to call ?
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Yes, that is right, each textUI.exe creates a new object of CListener; the I create a pointer to the object: pListener.
At the beginning I tryed just to pass the pointer to the DLL, and to execute the function like this:
pListener->MyFunction();
but as CListener is also defined inside the DLL and an object instanstiated; instead of executing the MyFunction from the object outside the DLL, it was the MyFunction from the object inside the DLL the one that was executed... Strange, I know.
I read information in Internet, and I saw that always when you want to call a function from a DLL (and this function is outside the DLL), it was necessary to pass the pointer to the function. I did that and it worked, but with the constraint that I mention in the first post...
|
|
|
|
|
IrenePwr wrote:
- but as CListener is also defined inside the DLL and an object instanstiated; instead of executing the MyFunction from the object outside the DLL, it was the MyFunction from the object inside the DLL the one that was executed... Strange, I know.
This is correct. The DLL has it's own memory space, and the run-time interpreted the pointer you passed. Because a similar object was found in this local space, the run-time thought that it must be this one.
I also doubt that you did not use GetProcAddress to get either the address or the function to return the address. Try doing it so that you export a function from the main module, and use GetProcAddress to get this function. The function just returns the address of the local CListener object. This ensures that the function executes in the address space of the main module, and thus the address returned points into the main module's memory area instead of the DLL's.
One more option would be to try to use __declspec(dllexport) on the class in the main module. This WILL limit the number of the objects instantated to a single one, because you can't export multiple objects with same signatures. This wouldn't be safe. Then using __declspec(dllimport) to create a pointer-to-class in the DLL, and it "should" discover the correct class, as it looks for it across the DLL boundaries.
Greatest problems arise due to the CListener class found inside the DLL. Could it be a viable option to create a copy of CListener class and rename it as CDLLListener , for example ?
This would change the signatures of the objects, and might thus allow us to use the pointers you mentioned without the danger that it'd point to the local object instead of the remote one.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
This getting interestingly strange.
I did a few prelimenary checks of my own, and found out that if your main executable module and the DLL have similar objects declared, then using GetProcAddress will fail, if the methods of the classes are not declared as virtual.
I had a class called CMyDLLClass , and the same header file was contained in the DLL as well. Now, both the main module and the DLL created objects of this type. When the methods of the class were all declared as virtual, the run-time interpreted the pointers correctly. If they were not virtual, then calling the members through the pointer in the main module ALWAYS called the methods of the object declared in the main module's context, regardless of which pointer I used. More interestingly, the pointers pointed to different locations in memory as well...
This starts to feel like a bug in the compiler or the optimizations it uses. Not sure yet, though..
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Whow!!
That can be what happens in my project also... I don´t have the functions in the header file inside the DLL declared as virtual.
I will check it tomorrow and I'll let you know...
Now I don't have the project in front of me anymore (it is at work )
Thanks for your help and interest
Irene
|
|
|
|
|
Hi,
Yes, it was that. If I define my functions inside the DLL as virtual, then the run-time interprets the pointers correctly.
Anyway, I find the same problem as before... just try to store the pointer of your class CMyDLLClass that you pass to your DLL, in a variable that is declared inside another class from your DLL... I cannot do that. I can only store the pointer if the variable is declared globally (outside any class)...
In any case, the code looks much better now, though...
Irene
|
|
|
|
|
Hello,
I'm trying to use the CopyFile function on my XP Pro computer but it keeps returning 5 (a.k.a. ERROR_ACCCESS_DENIED). What do I need to do to make it copy? Do I need to mess with tokens? If so which one?
wWw.KruncherInc.cOm - My cool programs
|
|
|
|
|
|
maybe insufficient access rights?
|
|
|
|
|
Then what do I need to do to have access?
OHHHHHH, I just found out the main problem, XPs not allowing me to copy to the windows directory, so how can I?
wWw.KruncherInc.cOm - My cool programs
|
|
|
|
|
Hi, i want to know how can i connect to different Table in using access DB? I'm using the ODBC method.. As i need to connect to differnet table to get data... plz help me, i want to know how to connect to different table.
Thank you for yr help...
|
|
|
|
|
Are you using MFC? If so, I assume you have a CRecordset object. Its GetDefaultSQL() method contains the name of the table being operated on. Either create another CRecordset that operates on a different table, or change the value being returned by the GetDefaultSQL() method.
"When I was born I was so surprised that I didn't talk for a year and a half." - Gracie Allen
|
|
|
|
|
I'm making an activex control using VS.Net 2003. The control will probably be used in VB mostly. I want to know how I can have enumerated constants show up (like in VB's MsgBox() function). Also, when I try to put in the return type for a function that would be considered a Boolean in VB, I don't see any data types that would map to VB's Boolean. And the 'Add Method' wizard tells me that I may only specify variant types of variables that are predefined in the list. Any help would be greatly appreciated.
If it's broken, I probably did it
bdiamond
|
|
|
|
|
Hai,
Is there any WM message sent to the main window while displaying another window (eg. a message box) or when that other window moves over the main window?
Thanks a lot.
|
|
|
|
|
When a message box is displayed or any other modal dialog box, then the main window will not be receiving any messages. The main window will receive WM_PAINT messages if there is another window over it (and not as big as it) which moves, because the OS will require the main window to redraw itself if another window on top of it changes position.
In your app, do you create the window which is over the main window? Is it modal or modeless? If it is modal and your app created the sub-window, you should handle the messages sent to that sub-window and then you can send any messages you want to the main window.
Sincerely,
Alexander Wiseman
Est melior esse quam videri
It is better to be than to seem
|
|
|
|
|
Hai,
Thanks a lot for ur reply.
Actually I have a main Dialog where in a particular region I do the drawing.
The problem is I cannot use WM_PAINT to draw. I have a common user defined function that gets the DC for the drawing. My app calls this function at many places and at each time the drawing is different which i manage using flags.
Now if I display a message box which is displayed over the drawing in turn erasing it. Or if I move the message box over my drawing it gets erased.
Since I cannot use WM_PAINT I dont know how to solve this problem.
Is there anyway to get rid of this?
Thanks again.
|
|
|
|
|
You could receive the WM_PAINT message anyway and, when there is a message box over your window, then call your custom drawing function inside the WM_PAINT message handler.
Is the WM_PAINT message being sent at all in your app right now, or are you just discarding it?
Sincerely,
Alexander Wiseman
Est melior esse quam videri
It is better to be than to seem
|
|
|
|
|
Hello,
You can work around this problem of the WM_PAINT message.
Anonymous wrote:
The problem is I cannot use WM_PAINT to draw. I have a common user defined function that gets the DC for the drawing. My app calls this function at many places and at each time the drawing is different which i manage using flags.
You can store the flags in member variables (or if there are not to may as a parameter for a WM_PAINT message).
The thing you do is call your drawing function from OnPaint() or put the drawing code into OnPaint(). Second, at every place you call your custom drawing function, you send a WM_PAINT message with the flags as parameters (or set the flags in member variables).
Good luck.
A student knows little about a lot.
A professor knows a lot about little.
I know everything about nothing.
|
|
|
|
|
Hi,
I'm new to COM programming and in need of a little help. I'm trying to test some DirectX Filters which are COM objects and have done the following:
I took a DirectX interface called IAMTVTuner and renamed it IAMTest. I want to see if it will still work under it's new name because I am going to end up doing some funky things with it. The problem I think is that the GUID is still associated with IAMTVTuner. I'm not sure how to either: associate the GUID with the IAMTest OR give the IAMTest a new GUID.
Is the association of GUIDs with COM objects and interfaces done in .idl files? I tried running Midl.exe on a file that I changed but I get errors. I'm not even sure if I'm on the right track.
Thanks
|
|
|
|
|
No, it will not work, and you've quite mistracked.
I suggest quickly renaming the interface back or you will corrupt your DirectX SDK installation for certain. If you rename the interfaces in the header files, and compile the code, then during execution, when you call the DirectX methods, you'll most likely cause serious errors. Or at least, your application will not do what it is supposed to. This includes crashing/damaging the OS and/or DirectX run-time.
Each COM object, and each interface they expose is considered unique. The Globally Unique Identifier (GUID) is used to identify these interfaces and objects on a global, around-the-world scale. If you created an interface that had the same GUID as DirectX's IAMTVTuner , then you'd be breaking a major rule of COM programming. In plain english, do not do this. Give your interface a new GUID, period. You can use the GUIDGEN.EXE to generate new GUIDs to use with your NEW interfaces.
If you need to extend the functionality offered by the IAMTVTuner interface, I suggest creating a standard C++ class that queries and uses the interface, while providing public functions that allow the user of class to do the "flunky things" you describe.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
What method do you think is best to control a view from another class, say for instance, a modeless dialog:
A: Let the dialog control the view directly.
B: Let the dialog talk directly to the view and have the view do all the work.
C: Route messages from the dialog to the view and let the view interpret the messages and do the work.
~Nitron.
ññòòïðïðB A start
|
|
|
|
|
In keeping with the MVC pattern and the philosophy of abstraction, I would offer a public method in the view class that exposes the appropriate functionality. This minimizes the contract between the view and its clients.
/ravi
My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
|