Like Tree1Likes
  • 1 Post By Codeplug

Can anyone help me with this? Odd application DLL pointer issue?

This is a discussion on Can anyone help me with this? Odd application DLL pointer issue? within the C++ Programming forums, part of the General Programming Boards category; I tried getting an answer for this on GameDev. Some good very helpful replies but generally speaking no adequate solution. ...

  1. #1
    Registered User
    Join Date
    Jan 2010
    Posts
    87

    Cool Can anyone help me with this? Odd application DLL pointer issue?

    I tried getting an answer for this on GameDev. Some good very helpful replies but generally speaking no adequate solution.

    I also made the mistake of asking on the IDE's forum. Last time I try that one. I value my sanity too much to ask anything again on there.

    So in the hope someone can actually answer my question without swooping in with the lock button like the world's biggest drama queen I thought I'd ask on here.

    I've had a few distanced and cold replies on here before but I've had many many helpful and detailed ones too (which is my own preferred brand of advice).

    So here goes:

    I've made an application and a DLL. The application loads the DLL and calls an API specific function within the DLL. Have a look:

    The function defined inside the DLL.

    Code:
    void CreateEffectFromFile(LPDIRECT3DDEVICE9 d3ddev,
                              LPCTSTR shaderFile,
                              LPD3DXEFFECT effect,
                              LPD3DXBUFFER errorLog,
                              D3DXHANDLE* technique)
    {
        HRESULT hr = D3DXCreateEffectFromFile(d3ddev, shaderFile, 0, 0, 0, 0, &effect, &errorLog);
    
        effect->FindNextValidTechnique(NULL, technique);
    
        return;
    }

    The application code that calls this:

    Code:
    LPD3DXEFFECT effect // global pointer within the application
    HMODULE m_hDLL // the DLL handler
    
    typedef void (*CREATEEFFECTFROMFILE) (LPDIRECT3DDEVICE9,
                                          LPCTSTR,
                                          LPD3DXEFFECT,
                                          LPD3DXBUFFER,
                                          D3DXHANDLE*);
    
    CREATEEFFECTFROMFILE _CreateEffectFromFile = NULL;
    
    ... sometime later ...
    
    void CreateEffectFromFileDLL(void)
    {
        m_hDLL    = NULL;
    
        m_hDLL = LoadLibrary("MyDLL.dll");
    
        if(!m_hDLL)
        {
            MessageBox(NULL,
            "Loading MyDLL.dll from lib failed.",
            "DLL Loading - error", MB_OK | MB_ICONERROR);
    
            return;
        }
    
        if (m_hDLL)
        {
            _CreateEffectFromFile = (CREATEEFFECTFROMFILE) GetProcAddress(m_hDLL, "CreateEffectFromFile");
            _CreateEffectFromFile(d3ddev,
                                  "specular.fx",
                                  effect,
                                  errorLog,
                                  &technique);
        }
    
        return;
    }
    All looks ok. But it does not work and here's the strange part. If the code is changed as follows:

    Code:
    LPD3DXEFFECT CreateEffectFromFile(LPDIRECT3DDEVICE9 d3ddev,
                              LPCTSTR shaderFile,
                              LPD3DXEFFECT effect, // unused in this method
                              LPD3DXBUFFER errorLog,
                              D3DXHANDLE* technique)
    {
        LPD3DXEFFECT tempEffect;
    
        HRESULT hr = D3DXCreateEffectFromFile(d3ddev, shaderFile, 0, 0, 0, 0, &tempEffect, &errorLog);
    
        tempEffect->FindNextValidTechnique(NULL, technique);
    
        return tempEffect;
    }

    ... and in the application

    Code:
    LPD3DXEFFECT effect // global pointer within the application
    HMODULE m_hDLL // the DLL handler
    
    typedef LPD3DXEFFECT (*CREATEEFFECTFROMFILE) (LPDIRECT3DDEVICE9,
                                          LPCTSTR,
                                          LPD3DXEFFECT,
                                          LPD3DXBUFFER,
                                          D3DXHANDLE*);
    
    CREATEEFFECTFROMFILE _CreateEffectFromFile = NULL;
    
    ... sometime later ...
    
    void CreateEffectFromFileDLL(void)
    {
        m_hDLL    = NULL;
    
        m_hDLL = LoadLibrary("MyDLL.dll");
    
        if(!m_hDLL)
        {
            MessageBox(NULL,
            "Loading MyDLL.dll from lib failed.",
            "DLL Loading - error", MB_OK | MB_ICONERROR);
    
            return;
        }
    
        if (m_hDLL)
        {
            effect = _CreateEffectFromFile = (CREATEEFFECTFROMFILE) GetProcAddress(m_hDLL, "CreateEffectFromFile");
            _CreateEffectFromFile(d3ddev,
                                  "specular.fx",
                                  effect,
                                  errorLog,
                                  &technique);
        }
    
        return;
    }

    This works. Why I have no idea.

    Simply put if I just make a pointer in the application, pass it into the DLL then the pointer is seen as valid in the DLL but NULL in the application.

    But if I make the function in the DLL return a temporary variable (or perhaps even the very pointer passed into it!) it is valid in the application and the methods of the class it points to can be called.

    Weird. It isn't a big problem because to keep encapsulation and API independency of the engine I'm working on all API specific stuff needs to be inside the DLL anyway, so there will never be a need to pass a pointer across an application into a DLL and hope it survives in this fashion.

    It would be nice to know why this happens though.

    Any ideas? thanks

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,680
    Code:
    int N = 5;
    
    void get_a_value(int a)
    {
       a = N;
    }
    
    void get_p_value(int *p)
    {
       p = &N;
    }
    
    void do_it_right(int **pp)
    {
       *pp = &N;
    }
    The first 2 functions don't work for the same reason yours doesn't. Could also use a reference parameter if not supporting a C API.

    gg

  3. #3
    Registered User
    Join Date
    Jan 2010
    Posts
    87
    I have much gratitude for your sane and decent reply thankyou.

    I also like very much that you haven't just explicitly stated the answer, I'm going to have to do a bit myself to figure it out, which means the knowledge will cement better.

    I'm doing some house work at the moment and once finished I'll try and find out exactly what knowledge is hidden in your post.

    Thanks so much

  4. #4
    Registered User
    Join Date
    Jan 2010
    Posts
    87
    Well I think this advice is amazing!! I remember reading something about this in a book called:

    C++ Common Knowledge by Stephen C. Dewhurst.

    A pointer to an object is not the same as a pointer to a pointer right? I re-rigged it using your method and hey presto the non-working method worked.

    Out of curiousity, does a pointer to an object end up slightly bound to that object some way? In such a fashion that it goes out of scope when a function exits, whereas to get a true safe global memory address (across the entire machine) so to speak you need a pointer to a pointer?

    I would really love to hear an explanation about this! Thanks

  5. #5
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    I don't think it has anything to do with pointers to an object being bound to that object and everything to do with "you can't change the value of something you pass into a function".

  6. #6
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    839
    a pointer holds the information telling you where a particular copy (often called an instance) of an object is located in memory (i.e. it's address).

    when you pass something by reference or pointer ( e.g. int& / int* ), you are passing the information about where to find this instance of the object

    when you pass something by value (e.g. int ) a new copy is made when it is passed into the function. the function is then operating on that copy, and has no idea where to find the original...

    it's a simple concept, but one that is often very confusing at first.

  7. #7
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,680
    Parameters in C/C++ are passed "by-value", which means the value is copied into another distinct variable:
    Code:
    void foo(int a)
    {
       // this 'a' is distinct, allocated off the stack
       a = 1;
       // 'a' goes out of scope, de-allocated back to the stack
    }
    
    int main()
    {
       int a = 2;
       foo(a);
       // a==2
    
       return 0;
    }
    Parameters that are pointers are no different. A pointers "value" is the address it points to, and is also passed by-value:
    Code:
    void bar(int *p)
    {
       p = (int*)1;
    }
    
    int main()
    {
       int *p = (int*)2;
       bar(p);
       // p==2
    
       return 0;
    }
    In C, there is no support for pass by-reference, but it can be simulated by passing a pointer (by-value) and dereferencing that pointer:
    Code:
    void foo(int *pa)
    {
       // modify main::a through derefernced pointer
       *pa = 1;
    }
    
    int main()
    {
       int a = 2;
       foo(&a);
       // a==1
    
       return 0;
    }
    C++ supports pass by-reference without having to use pointers:
    Code:
    void foo(int &a)
    {
       // modifies main::a directly
       a = 1;
    }
    
    int main()
    {
       int a = 2;
       foo(a);
       // a==1
    
       return 0;
    }
    In your case, we have a C function that has output parameters that are themselves pointers. So to simulate pass by-reference, we pass a pointer to those pointers.
    Quote Originally Posted by MSDN
    Code:
    HRESULT D3DXCreateEffectFromFile(
      __in   LPDIRECT3DDEVICE9 pDevice,
      __in   LPCTSTR pSrcFile,
      __in   const D3DXMACRO *pDefines,
      __in   LPD3DXINCLUDE pInclude,
      __in   DWORD Flags,
      __in   LPD3DXEFFECTPOOL pPool,
      __out  LPD3DXEFFECT *ppEffect,
      __out  LPD3DXBUFFER *ppCompilationErrors
    );
    The second to last parameter is "ID3DXEffect **ppEffect". The following code demonstrates the intention:
    Code:
    void bar(int **p)
    {
       *p = (int*)1;
    }
    
    int main()
    {
       int *p = (int*)2;
       bar(&p);
       // p==1
    
       return 0;
    }
    So if you want "effect" and "errorLog" to also be output parameters of CreateEffectFromFile(), then they need to have the same type that D3DXCreateEffectFromFile() uses.
    Code:
    void CreateEffectFromFile(/*in*/ LPDIRECT3DDEVICE9 d3ddev,
                              /*in*/ LPCTSTR shaderFile,
                              /*out*/LPD3DXEFFECT *ppEffect,
                              /*out*/LPD3DXBUFFER *ppErrorLog,
                              /*out*/D3DXHANDLE *pTechnique)
    {
        HRESULT hr = D3DXCreateEffectFromFile(d3ddev, shaderFile, 0, 0, 0, 0, 
                                              ppEffect, ppErrorLog);
        // ... 
        (*ppEffect)->FindNextValidTechnique(NULL, pTechnique);
        // ... 
    }
    gg

  8. #8
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    839
    i think there's some errors in your code dude...
    Code:
    int* p = (int*)2;
    at best, that's a very confusing example.

  9. #9
    Registered User
    Join Date
    Jan 2010
    Posts
    87
    Quote Originally Posted by m37h0d View Post
    i think there's some errors in your code dude...
    Code:
    int* p = (int*)2;
    at best, that's a very confusing example.
    Oh don't worry about that mate - but thanks for pointing it out.

    Personally I am delighted at the responses in this thread. Looks like I still have so much to learn. I thought just passing a pointer in would be ok but what I underestimated was that the function arguments, although containing a pointer, are essentially making a copy of that pointer just as if I were passing an integer into the function. The function ends and the local variable I thought was global gets deleted and that's the end of that. I mistakenly thought passing a pointer in was fine, but obviously it isn't. You end up with a copy of that pointer by the looks and so makes sense why it was valid in the DLL but not in the application.

    What a dummy. Another n00b getting confused over pointers. Whoops.

    Anyways thanks to you guys especially you Code Plug but to all others too I can at least begin to figure out for myself why this is happening now. I'll be honest I took code protocol for granted when reading beginners books but the big boys stuff of the real world is alot deeper than those books suggest, and for fair reasons too.

    I'm off out fishing for the night tonight when I get back tomorrow (after having blanked again no doubt) I'll give the new content in this thread more just attention.

    Thanks

  10. #10
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,823
    Just a little FYI... since if you have a pointer to something, that something won't get deleted when the pointer goes out of scope (because it isn't bound to what it's pointing to in any way), the standard library carries "special pointers" that do delete whatever they point when they go out of scope. They're called smart pointers, and include std::shared_ptr, std::unique_ptr, and std::weak_ptr.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,680
    >> i think there's some errors
    Nope. They all compile as C99 and C++03, and are well-defined.

    >> that's a very confusing example
    It was meant to convey the fact that pointer variables store values - just like int variables store values. And just like an int parameter, pointer parameters are passed by-value. Once that's well understood, confusion should subside.

    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. pointer issue
    By Nuggnugg in forum C Programming
    Replies: 15
    Last Post: 03-31-2011, 01:52 PM
  2. not a pointer issue
    By ~Kyo~ in forum C++ Programming
    Replies: 45
    Last Post: 04-21-2010, 05:51 PM
  3. Pointer issue
    By pfs in forum C Programming
    Replies: 2
    Last Post: 09-26-2008, 11:37 AM
  4. (Gnome) X Windows Application Issue
    By stickdeoderant in forum Linux Programming
    Replies: 0
    Last Post: 05-21-2007, 10:41 AM
  5. C++ pointer issue
    By yongzai in forum C++ Programming
    Replies: 8
    Last Post: 12-22-2006, 03:27 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21