Results 1 to 15 of 15

Thread: What exactly are the parameters for the API method called DispCallFunc?

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    What exactly are the parameters for the API method called DispCallFunc?

    Looking at MSDN I see
    Code:
    HRESULT DispCallFunc(
       void       *pvInstance,
       ULONG_PTR  oVft,
       CALLCONV   cc,
       VARTYPE    vtReturn,
       UINT       cActuals,
       VARTYPE    *prgvt,
       VARIANTARG **prgpvarg,
       VARIANT    *pvargResult
    );
    Some of these are confusing, because they don't specify a byte-size for the parameter, but instead give it in some cryptic way that is great for VC++, but not so great for those wanting to figure out how to use it in VB6.

    For example, what is a "void"? I thought it meant "don't fill in this parameter, because it's unused", but I'm not sure. Some are obvious like ULONG_PTR, means an unsigned long value which holds a memory address (a pointer). VB6 doesn't have any unsigned Long, but it has the standard (signed) Long, which should usually work. Other cryptic ones are VARTYPE. What type of variable is a VARTYPE? Is it equivalent to a Long in VB6? Or is it the equivalent to an Integer in VB6 (what VC++ calls a Short)?

    And for goodness sake, what is a VARIANTARG? I think (based on some other things I've read), this is where I feed some pointers to the input parameters to the function that is to be called, to the DispCallFunc method. But what kind of input is it expecting?
    Is it expecting an array of Long values that are pointers? Is it expecting a Variant that holds an array of Long values that are pointers? Is it expecting an array of Variants that hold Long values that are pointers? Or is it expecting a Variant that holds an array of Variants that hold Long values that are pointers?

    Any help here at using this in VB6 would be great. There are hardly any examples on the net that show its use at all (even in C based languages), and from what I can tell, there are none that show its use in VB6.

    I wish there was just some tutorial that said "These are the data types of the parameters of the DispCallFunc method, and here's what the function expects you to put into them. ......". But nope, nothing of the sort. Can somebody here on VbForums just explain straight out, what is the correct declare statement for this thing, and how do I use it to call a variety of different methods in my Module1 module? Some things I'd like to know how to use it with are:
    A function with no input parameters, but with an output parameter (like maybe a random number generator).
    A function with some input parameters, and a return value.
    A sub with some input parameters, and no return value.
    A sub with no input parameters, and no return value (but maybe it does something else, like clear the screen)
    Calling a function or sub that is not in my Module1 module, but rather in an STDCALL DLL file.
    Calling a function or sub that is not in my Module1 module, but rather in an CDECL DLL file.
    Calling a function or sub that is in a COM object (such as from an ActiveX DLL or OCX file)
    Calling a function or sub that is in a VB6 Class (such as a method in Class1)

    Any help with its general use (like how to properly declare it, and what the parameters mean), and any help for these specific listed uses from someone who's an expert at using DispCallFunc, would be very helpful.

  2. #2
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: What exactly are the parameters for the API method called DispCallFunc?

    Quote Originally Posted by Ben321 View Post
    ... There are hardly any examples on the net that show its use at all (even in C based languages), and from what I can tell, there are none that show its use in VB6...
    I've seen that used in a number of recent threads.
    Did you type DispCallFunc in the Forum search box above on the forum tab page line and do a search?
    There appears to be at least 26 other threads, besides this one, that mention it, and quite a few, it seems to me, examples of code using it, almost all, if not all, being from VB6.
    Last edited by passel; Jun 16th, 2015 at 07:00 AM.

  3. #3
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: What exactly are the parameters for the API method called DispCallFunc?

    You can take a look at my project that is based on that API. Within the class I've added lots of comments. If they don't answer your questions directly, they may give some clues/links that may help. That project has examples of calling stdCall/CDecl DLLs, VB object methods, and VB class methods (post #16 in that thread). Parameters and/or return value combinations as you questioned are handled.

    Note: There is no advantage of using the API to call exposed methods of VB objects/classes. There is no intellisense for the API but VB provides it with its objects/classes. Also there is no real advantage of using the API over declaring individual stdCall API functions. My opinion of course.

    FYI: Void means 'optional' and a pointer in this case. If not provided, then zero would be used. Optional in this case does not mean you can ignore the parameter, it means its value can be a Null. The other types are defined, just a matter of locating them
    VarType
    VARIANTARG is Variant (a list of Variants)
    CALLCONV (Enum so Long)

    The asterisks are key here. They indicate a pointer is wanted. Pointers are Longs or the value should be passed ByRef. Double asterisks are pointers to pointers (far pointers)

    VB example of pointer to pointer:
    - StrPtr(Me.Caption) is a pointer to a string; ObjPtr(Me.Icon) is a pointer to an Object
    - VarPtr(Me.Caption) is a pointer to the pointer: StrPtr(), similar: VarPtr(Me.Icon)
    And in some odd cases, to provide a pointer to a pointer, you may need 2 variables to pass one variable. Let's say an API wanted a pointer to a pointer of an Integer
    Code:
    Dim intX As Integer, fPointer As Long
    intX = 1
    fPointer = VarPtr(intX)
    ' then pass VarPtr(fPointer) to the API (ByVal) or simply pass fPointer ByRef
    Last edited by LaVolpe; Jun 16th, 2015 at 12:30 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  4. #4

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Re: What exactly are the parameters for the API method called DispCallFunc?

    Thanks for the info. I finally figured it out, though I didn't see your reply post before I managed to figure it out. I found some other places on the net that had some info (which I wasn't completely sure about), and combined with the info already in MSDN, and what I learned by trial and error on my own, I managed to figure out how to make it work.

    Here's the declaration that I believe is the best declaration for it.
    Code:
    Private Declare Function DispCallFunc Lib "oleaut32.dll" ( _
    ByVal pvInstance As Long, _
    ByVal oVft As Long, _
    ByVal cc As Integer, _
    ByVal vtReturn As Integer, _
    ByVal cActuals As Long, _
    ByRef prgvt As Integer, _
    ByRef prgpvarg As Long, _
    ByRef pvargResult As Variant) As Long
    And here's the descriptions I would give to each of the parameters, which much better explains how to use DispCallFunc than anything on the MSDN website.
    pvInstance is only needed if the function is in an instance of an Object. If the function is in an Object, this value is the memory address obtained by using ObjPtr on the Object that contains the desired function.
    Otherwise it's zero.

    oVft is the address of the memory location of the function, if it is not in an Object.
    If the function is in an Object, then oVft instead is the offset in that Object's VTable.

    cc is the calling convention.
    FASTCALL=0
    CDECL=1
    STDCALL=4

    vtReturn is the data type of the return value.
    The usable values can be found in the VbVarType Enum in VB6.

    cActuals is the number of parameters of the function.

    prgvt is a pointer to an array that specifies the data type for each parameter.
    The usable values can be found in the VbVarType Enum in VB6.
    Because ByRef is used, this argument can be directly given the first element of an Integer array.
    No VarPtr is needed here.

    prgpvarg is a pointer to an array of Longs that hold pointers that point to variables of type Variant that hold the parameters for the function.
    Because ByRef is used, this argument can be directly given the first element of a Long array.
    No VarPtr is needed here.

    pvargResult is a pointer to a Variant that holds the return value of the function.
    Because ByRef is used, this argument can be directly given a Variant type variable.
    No VarPtr is needed here.

  5. #5
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: What exactly are the parameters for the API method called DispCallFunc?

    Quote Originally Posted by Ben
    ...
    pvInstance is only needed if the function is in an instance of an Object. If the function is in an Object, this value is the memory address obtained by using ObjPtr on the Object that contains the desired function.
    Otherwise it's zero.
    ...
    A unique exception to the above
    - non-zero = pointer to the memory address of the object's VTable
    - zero = the memory address of a function. If the function belongs to a an object, then the first item in prgpvarg will be the instance of that object.

    Just FYI, it is possible to call a function directly from an object if you know the function's memory address. Therefore, it is entirely possible to call a non-public method of a class assuming you know the address of that method
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  6. #6

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Re: What exactly are the parameters for the API method called DispCallFunc?

    Quote Originally Posted by LaVolpe View Post
    A unique exception to the above
    - non-zero = pointer to the memory address of the object's VTable
    - zero = the memory address of a function. If the function belongs to a an object, then the first item in prgpvarg will be the instance of that object.
    So the value I'm supposed to put in the lpInstance parameter is not the value returned by ObjPtr then? I believe the value returned by ObjPtr is actually a pointer to the pointer that points to the VTable, and not itself a pointer to the VTable. I had just assumed (since I had never used it to work with objects before) that the lpInstance parameter was supposed to be the the value returned by ObjPtr, and that then the DispCallFunc function would internally use that value to find the VTable pointer, which it would then use to find the VTable, so as to make the use of DispCallFunc as simple as possible, requiring the end user to go through minimal effort to prepare the inputs to the DispCallFunc function.

  7. #7
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: What exactly are the parameters for the API method called DispCallFunc?

    No, you are correct. My wording may be misleading. The intent of my reply was to note that it is possible to call a private method/function of a VB object if that function address is known. Does require passing ObjPtr(thatClass) as the 1st entry of the prgpvarg list. This is because COM functions receive as the 1st parameter a reference to the class being called. VB hides this from us when we call a class function, but the low-level DispCallFunc API requires it in that specific case.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  8. #8

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Re: What exactly are the parameters for the API method called DispCallFunc?

    Getting unexpected error when using it with a test class.

    My form's code is
    Code:
    Private Declare Function DispCallFunc Lib "oleaut32.dll" (ByVal pvInstance As Long, ByVal oVft As Long, ByVal cc As Integer, ByVal vtReturn As Integer, ByVal cActuals As Long, ByRef prgvt As Integer, ByRef prgpvarg As Long, ByRef pvargResult As Variant) As Long
    
    Dim MyClass As New Class1
    
    Private Sub Command1_Click()
    Dim ArgTypes(1) As Integer
    Dim ArgPtrs(1) As Long
    Dim Arg0 As Variant, Arg1 As Variant
    Dim RetVal As Variant
    
    Arg0 = 4&
    Arg1 = 5&
    
    ArgTypes(0) = VarType(Arg0)
    ArgTypes(1) = VarType(Arg1)
    
    ArgPtrs(0) = VarPtr(Arg0)
    ArgPtrs(1) = VarPtr(Arg1)
    
    Print Hex$(DispCallFunc(ObjPtr(MyClass), 4 * 7, 4, vbLong, 2, ArgTypes(0), ArgPtrs(0), RetVal))
    Print RetVal
    End Sub
    My class's code is
    Code:
    Public Function Func(ByVal a As Long, ByVal b As Long) As Long
    Func = a + b
    End Function
    When I click the command button, the function Func in the MyClass instance of the class Class1 does get called, but then something unexpected happens. It doesn't return the the value of the function properly into the RetVal Variant variable. That variable remains empty, and the DispCallFunc function returns error code &h80020010 which according to MSDN means "Invalid callee". Can you please tell me what's going wrong here?

  9. #9
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: What exactly are the parameters for the API method called DispCallFunc?

    Without trying your code, I see that the calling convention is declared in the API as Integer, it should be Long. Try changing that and see if it works as expected
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  10. #10

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Re: What exactly are the parameters for the API method called DispCallFunc?

    Quote Originally Posted by LaVolpe View Post
    Without trying your code, I see that the calling convention is declared in the API as Integer, it should be Long. Try changing that and see if it works as expected
    Ok, I tried it, and it still doesn't fix it. Same error. Could you please try my code, and see what's wrong with it? Maybe compile to an EXE file, and run it through a debugger like OllyDbg, and see if you can find out what's really going on inside the code, that's causing this problem, at the very low "assembly code" level, if it's not obvious from looking at the VB6 code?

  11. #11
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: What exactly are the parameters for the API method called DispCallFunc?

    The calling convention parameter, not the return type parameter. Here is my declaration for that API & have been using it without issues for 10+ years.
    Code:
    Private Declare Function DispCallFunc Lib "oleaut32.dll" (ByVal pvInstance As Long, ByVal offsetinVft As Long, ByVal CallConv As Long, ByVal retTYP As Integer, ByVal paCNT As Long, ByRef paTypes As Integer, ByRef paValues As Long, ByRef retVAR As Variant) As Long
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  12. #12

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Re: What exactly are the parameters for the API method called DispCallFunc?

    Quote Originally Posted by LaVolpe View Post
    The calling convention parameter, not the return type parameter. Here is my declaration for that API & have been using it without issues for 10+ years.
    Code:
    Private Declare Function DispCallFunc Lib "oleaut32.dll" (ByVal pvInstance As Long, ByVal offsetinVft As Long, ByVal CallConv As Long, ByVal retTYP As Integer, ByVal paCNT As Long, ByRef paTypes As Integer, ByRef paValues As Long, ByRef retVAR As Variant) As Long

    Sorry, I misread that. My above reply would not have even been posted if I'd read it correctly. But I edited it to reflect that, and instead posted something else in its place. Sadly, you never seemed to see the edited version of my post, which no longer has anything to do with what it originally said, but your reply is based on what it originally said, so your reply now seems completely out of place.

    But, for your convenience, I'm not going to ask you to go back and re-read my edited post. Instead, I've posted a copy of it below in the quote box

    Ok, I tried tried changing the cc parameter to Long, and it still doesn't fix it. Same error. Could you please try my code, and see what's wrong with it? Maybe compile to an EXE file, and run it through a debugger like OllyDbg, and see if you can find out what's really going on inside the code, that's causing this problem, at the very low "assembly code" level, if it's not obvious from looking at the VB6 code?
    I strongly request that you read this, and reply to it, and acknowledge that your suggested fix did in fact not fix anything. I'm starting to get desperate now, because code that seems like it SHOULD work, in fact does NOT work.

  13. #13
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: What exactly are the parameters for the API method called DispCallFunc?

    Which post are you calling your edited post?
    <edit> I do see you quoted it in post #12. Yes, we don't see your edits for some reason. </edit>
    Your code in Post #8 has this declaration
    Code:
    Private Declare Function DispCallFunc Lib "oleaut32.dll" (ByVal pvInstance As Long, ByVal oVft As Long, ByVal cc As Integer, ByVal vtReturn As Integer, ByVal cActuals As Long, ByRef prgvt As Integer, ByRef prgpvarg As Long, ByRef pvargResult As Variant) As Long
    You see it says cc As Integer. That should be cc As Long.
    So, are you saying you did fix that?
    <edit> I do see you quoted it in post #12. Yes, we don't see your edits for some reason. </edit>
    Last edited by passel; Jun 17th, 2015 at 05:20 PM.

  14. #14

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Re: What exactly are the parameters for the API method called DispCallFunc?

    It would help if people remembered to press F5 to refresh their browser window and quickly reread the post they just read, just before replying, to make sure they are replying to the most recent version of the post and that there hasn't been some major change in the content of the post that they are replying to.

    Back on topic, other than the declaration being wrong (which I now fixed), do you see anything, anything at all that looks misplaced? If not, please tell me why this isn't working? Are classes like Class1 in VB6 not handled the same way as compiled objects (such as ActiveX DLL files)? For DispCallFunc to work with an instance of an object, does that object need to be in an already compiled and properly registered ActiveX DLL file, rather than as a Class within the project itself, such that the correct term would be Object rather than Class when describing it?

  15. #15
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: What exactly are the parameters for the API method called DispCallFunc?

    I wouldn't call VB class methods this way. But agreed, doesn't work using that API, that way. In ASM thunks, we call the method by its function address, passing the instance of the class and whatever parameters it requires. There is some stack corruption occurring when trying to call a VTable offset in this case. If you change passed parameters so function returns a unique value, you will notice it gets put in one of the other parameters you passed to DispCallFunc. Bottom line, to use that API to call classes, maybe passing zero as the first parameter and then passing ObjPtr() as the first of the prgpvarg values? I'll leave that to you to experiment with. VB class methods can be called by name within VB, so I consider what you are attempting as an exercise, likely not used in any real sense. GL
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width