Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Interface problem with custom VFP COM component...

Status
Not open for further replies.

rlawrence

Programmer
Sep 14, 2000
182
US
Hi folks,

I have already posted this problem on the ASP forum: thread333-1688356

The problem appeared when I attempted to incorporate a new method in my component--which is being used in a web application. I am at the point where I have verified that the problem is not with ASP or IIS. I've created an EXE using my VFP test program. The test program works fine on my development machine, but when I run it on the server, I get the following message at the point where the new method is called:

OLE IDispatch exception code 0 from ?, ?..

This seems like a straight forward problem with the interface, but I haven't been able to resolve it. I have uninstalled and reinstalled the product. I have used REGSVR32 to unregister and re-register the DLL. I think this is not pertinent, but the DLL is installed as a COM+ component. I have removed and reinstalled the DLL through the Component Manager. None of these steps have changed the behavior.

When I look at the interface through the component manager, I can clearly see the component in question, and the new method that I added.

I have been searching everywhere for strategies for resolving this, so far to no avail. Can anyone here help?

Thanks,
Ron
 
IIS and ASP.Net run as a service and it might be running under a different username on the server.

you might need to register the DLL as Admininistrator.



Ali Koumaiha
TeknoSoft Inc.
Michigan
 
Thanks for the quick responses. The reason the DLL is installed in COM+ has to do with security. Essentially, I don't want to grant the anonymous user access to the database. So, the component is invoked under a different user. But none of this is pertinent to the problem.

In this last stage of testing, I created a test program. It was my original functional test in VFP. I made sure that the test program would bind with the component using the installed name. e.g.

Code:
rmcInvoice = createobject("paweb.rmcInvoice")

I've tested the test program outside of VFP on my development machine. It works fine. When I move the test program to the server, run it from my administrative account, it fails at the point of the new method call, and presents the error message I posted above.

I know that the component has been instantiated, because earlier calls to its methods work fine. The offending call is highlighted in red.

Code:
rmcInvoice = oWeb.webInvoice.rmcInvoice
rcInvoice = oWeb.webInvoice.rcInvoice

? "Order Date: "
?? rcInvoice.rsOrder.oRecord.Order_Date
? "Order Prior Discount: "
??rcInvoice.rsOrder.oRecord.Discount
? "Discounted items? "
??rmcInvoice.rmI.DiscountedItems(rcInvoice.rsItem)
? "Order Prior Total: "
??rcInvoice.rsOrder.oRecord.Total
? "Order Prior Comment: "
??rcInvoice.rsOrder.oRecord.Comment

?"*************** Apply a Promotion ****************"
? "Results of AddPromotion()? "
IF [COLOR=red]rmcInvoice.AddPromotion(rcInvoice, "TESTDEDUCT")[/color]
	?? "Success!"
ELSE
	?? rcInvoice.rsOrder.cMessage
ENDIF

All attempts to uninstall/re-install or unregister/re-register paweb.dll have not changed this behavior.
 
IIS adds another level of complexity.

-Your app needs to run in the 32bit application pool to make use of 32bit COM classes.

Also look into COM+ Applications:

-Component Services -> Computers -> My Computer -> COM+ Applications
-Open a COM+ Application object.
-Open Components.
-Right-click on your class and select Properties.
-Under "Advanced" there is a check box for "Allow IIS intrinsic properties".

Bye, Olaf.
 
Also, to make sure IIS runs 32bit apps.
from the dos prompt:
cscript %SYSTEMDRIVE%\inetpub\adminscripts\adsutil.vbs SET W3SVC/AppPools/Enable32bitAppOnWin64 1

Ali Koumaiha
TeknoSoft Inc.
Michigan
 



Insert this function in your server class definition, so you can get the actual error from your com component, and not the generic 'OLE IDispatch exception code 0 from ?, ?..'

*-------------------------------------------
FUNCTION Error(nError, cMethod, nLine)
*-------------------------------------------
COMreturnerror(cMethod+' err#='+str(nError,5)+'line='+str(nline,6)+' '+message(),_VFP.ServerName)

*-------------------------------------------

Marco
 
Hi Marco,

Thanks for the suggestion. I have to go back and stare at this a bit more, but my first attempt at introducing COMReturnError() caused a generic "OLE IDispatch..." error in my development environment! I haven't decided yet whether this is progress or not. The error handler is returning no good failure information so far.

Olaf and Ali,

Theo only thing I see on the Advanced properties for the rmcInvoice component is, "Queuing Exception Class". Nothing for "Allow IIS intrinsic properties". I'm pretty well convinced at this point that I am NOT dealing with either an IIS or COM+ issue--since my test program (written in Foxpro) calls the component directly and fails in the same place where the ASP page fails.

Now to go back and see what I am doing wrong with COMReturnError(). That still looks promising, but there's not much help in the documentation for using it. Thanks all for your thoughts.

Ron
 
Good news and bad news...

The good news is that the error is now occuring in exactly the same place on my development machine. After rebuilding the DLL, I now run the test program from within VFP and I get the OLE IDispatch error.

The bad news is that there is no new information from this error. It is simply a generic OLE error. Now I had an Error method in my component prior to Marco's suggestion. If I do NOT submit the rcInvoice parameter, then my error method logs an error to the error log. When I submit rcInvoice as a parameter again, the procedure never gets to the Error() method because the failure occurs because it CAN'T get to the new method, AddPromotion().

Taking Marco's suggestion short-circuited this process, but the result is the same.

So, the only thing I have succeeded in doing is to move the interface problem to my development machine. I'm still missing something basic in my understanding of COM.
 
Let's piece this together one step at a time. Does the error happen when you instantiate the component or when you call the new method? Do older methods still work?

Craig Berntson
MCSD, Visual C# MVP,
 
I can instantiate the component.

Old methods work fine.

I just added another new method for testing purposes and it fails as well.

F.Y.I. I have been pouring through my registry (on my development machine) to remove all obsolete references to the component.
 
COMRETURNERROR() does add info into the OLE error exception, you still have to call AERROR() after you got the OLE ERROR, to get at the value the Error() method added via COMRETURNERROR(). That's described in the COMRETURNERROR() help topic. Read the AERROR() help topic to see what to do and expect in case of an OLE error in the first place.

What if you test this in VFP: Use the class as normal, not via it's OLE class name, eg include the DEFINE CLASS or VCX or whatever your COM class is composed of. Now do the same stuff with the class instance and you get native VFP errors. If there is no error calling obj.AddPromotion() then, you at least know the code is ok in principle.

And last not least: Are you aware compiling in VFP tries to update reg info about the COM class(es), but fails due to UAC? Are you aware you can fix that by starting VFP9.exe via right click and choosing "Run as Adminstrator"?

Bye, Olaf.
 
Hi folks,

Actually, Olaf, I'm running VFP7. I do start it as administrator for just that reason--though my knowledge of the details is weak.

I'm guilty of flailing a bit here. Although my recent tests have been via VFP, I have been using the registered component to test the DLL. I had already successfully tested the class in VFP by accessing it directly. But...

When I stepped back, used my most recent testing procedure, but altered it to instantiate the class(es) directly, I found an error! :-/

I've still got some questions about error handling. Actually, I have several other questions as well, but I'm going to take the time now to rebuild the application and try it on the server. I'll be back with the results.

Thanks for the help.
 
O.K. I haven't tested my DLL on the server yet, but I think I have shed some light on how there could have been an error that I didn't catch. I had tested the function pretty extensively in VFP before building a kit to install on the server. And, I was CONVINCED that it was working.

My test program is in a PRG file called, TESTPROMOTION2.PRG. It prints out several things to show the progress of the test. I have changed the order of some of these things as I have worked through this problem. Generally, I run the test program as follows...

Code:
DO TestPromotion2

In my most recent tests, I noticed that the printout wasn't in the order that I expected. It was from an older version! So, I did a directory of TestPromotion.* and found the .BAK and .FXP extensions. I deleted both and manually recompiled my test procedure. I ran the above command again and STILL got the old printout.

If, however, I right click on the PRG window to execute it, I get the correct printout. I notice now, that the above command gives me the correct printout.

So, it seems likely, that I made a change to a subprocedure toward the end of my preliminary testing in VFP, and my test procedure ran fine. I figured I was good to go! Man! This has cost me a lot of time.

Once again I ask, "What am I missing???" It seems VFP is caching the procedure somewhere, even if I save the procedure, delete the FXP, and recompile?
 
Well, once again, my test program works on my development machine, outside of VFP, but fails at the call to AddPromotion() on the server. It's the same "OLE iDispatch exception 0" message.

Interestingly, I've added a new method, ClearPromotions(), which is also in the test procedure. It seems to work fine on the server.

I just unregistered and re-registered PAWeb.dll. I get the same result.

It's 2:40 EDT... I'm ready for a drink...[neutral]
 
DO someprg

Look out what paths vfp searches and what it actually executes. Besides an fxp being still older code, you can also run a totally different prg/fxp from a folder. Perhaps first CD To the folder of the prg.

Also nobody can tell you what's wrong with your code without neither error nor code itself. The call of a method can fail, if you pass in more parameters than are allowed by lparameters or parameters in the procedure definition. There can be all kind of problems.

Try again with the error handling.

In the first place let's try with a simplistic com server just to demonstrate error handling:
Code:
Define class mycom as Session olepublic
   Procedure AddPromotion()
      LParameters param1, param2
   EndProc
   
   Procedure Error()
       LParameters nError, cMethod, nLine
       COMreturnerror(cMethod+' err#='+str(nError,5)+'line='+str(nline,6)+' '+message(),_VFP.ServerName)
   Endproc
EndDefine

Compiled to a COM DLL and now use it with the extended error reporting:
Code:
On Error AERROR(gaError)
o = Createobject("mydll.mycom")
o.AddPromotion(1,2,3) && one parameter too much
set step on
* now inspect the gaError array in the debugger Locals windows.

Bye, Olaf.
 
The problematic part may be passing in an OLE object to another. In general you can pass objects, also ole objects, but this is suspicious.

Code:
rmcInvoice = oWeb.webInvoice.rmcInvoice
rcInvoice = oWeb.webInvoice.rcInvoice
...
...
... 
IF rmcInvoice.AddPromotion(rcInvoice, "TESTDEDUCT")
...

If rmcInvoice is an ole object, I assume rcInvoice is too. Are you sure you're having both the right type of objects? What if you test each objects class, baseclass, and check for PEMSTATUS() of the Method and the properties you want to use or address before doing so.

Bye, Olaf.
 
Hi Olaf,

Thanks for your persistence.

I believe I have done what you suggest with AError(). It's right out of the sample in the help. Nothing of value is returned. The array is empty.

If this is suspicious...
Code:
rmcInvoice.AddPromotion(rcInvoice, "TESTDEDUCT")
...then I'm really in trouble. This is typical of the automation calls I make in the web application. rmcInvoice is essentially the business logic class. rcInvoice is the data container class. rcInvoice is passed to most rmcInvoice methods. I do so in the test procedure prior to and after the call to AddPromotion().

One thing I noticed yesterday that is a little unusual is that AddPromotion is defined as a FUNCTION. Most of the other methods are defined as PROCEDUREs. AddPromotion passes back a value of True or False to indicate whether the application of the submitted promotion was successful.

I see nothing wrong with declaring the method as a function. It's just that it is unusual for the rmcInvoice class. It is certainly not unique. Anyway, it works in both VFP and in the test program outside of VFP on the development machine.

I generally try not to pour out a bunch of code for others to have to pour through, but perhaps including my test program will help. So here it is. It's not terribly long. I've highlighted the significant calls to components in red.

Code:
* Used for testing the addition of a promotion to an invoice.
* This procedure differs from TestPromotion in that it uses PAWeb.Dll
* and the WebMgr component--rather than accessing rmcInvoice directly.

CLEAR ALL
CLEAR
SET MEMOWIDTH TO 150
*ON ERROR DO errhand     && errhand is the error handler procedure

oWeb = CREATEOBJECT("paweb.webmanager")
*!*	DO pasetup
*!*	oWeb = CREATEOBJECT("webmanager")
cPath = SYS(5)+SYS(2003)
?oWeb.InitSession(cPath)

?"*************** Capture an order ****************"
?oWeb.webInvoice.InitInvoice()
? "Data Path: "
??oWeb.webInvoice.rcInvoice.rsOrder.cDataPath

*!*	rcInvoice.rsOrder.oRecord.order_key =      39363
*!*	? "Retrieve the order? "
*!*	??oWeb.webInvoice.Select(26202, 1) && Same as order key 39363.
? "Able to retrieve the order? "
IF ![COLOR=red]oWeb.webInvoice.Select(1353, 1)[/color] && Same as order key 1355
	? "Order was not found."
	? oWeb.webInvoice.rcInvoice.rsOrder.cMessage
	RETURN
ENDIF
WAIT "Hit enter to continue..."

rmcInvoice = oWeb.webInvoice.rmcInvoice
rcInvoice = oWeb.webInvoice.rcInvoice
?
? "*************** Show Invoice ****************"
?[COLOR=red]rmcInvoice.ShowInvoice(rcInvoice)[/color]

WAIT "Hit enter to continue..."

? "Order Date: "
?? rcInvoice.rsOrder.oRecord.Order_Date
? "Order Prior Discount: "
??rcInvoice.rsOrder.oRecord.Discount
? "Discounted items? "
??[COLOR=red]rmcInvoice.rmI.DiscountedItems(rcInvoice.rsItem)[/color]
? "Order Prior Total: "
??rcInvoice.rsOrder.oRecord.Total
? "Order Prior Comment: "
??rcInvoice.rsOrder.oRecord.Comment

?
?"*************** Apply a Promotion ****************"
? "Results of AddPromotion()? "
IF [COLOR=red]rmcInvoice.AddPromotion(rcInvoice, "TESTDEDUCT")[/color]
	?? "Success!"
ELSE
	?? rcInvoice.rsOrder.cMessage
ENDIF
? "Order Post Discount: "
??rcInvoice.rsOrder.oRecord.Discount
? "Order Post Comment: "
??rcInvoice.rsOrder.oRecord.Comment
? "Order Post Adjustment: "
??rcInvoice.rsOrder.oRecord.Adj_Type_1
??rcInvoice.rsOrder.oRecord.Adjustmnt1
? "Order Post Total: "
??rcInvoice.rsOrder.oRecord.Total

WAIT "Hit enter to continue..."


?
?"*************** Clear Promotions ****************"
[COLOR=red]rmcInvoice.ClearPromotions(rcInvoice)[/color]
? "Order Post Discount: "
??rcInvoice.rsOrder.oRecord.Discount
? "Order Post Comment: "
??rcInvoice.rsOrder.oRecord.Comment
? "Order Post Adjustment: "
??rcInvoice.rsOrder.oRecord.Adj_Type_1
??rcInvoice.rsOrder.oRecord.Adjustmnt1
? "Order Post Total: "
??rcInvoice.rsOrder.oRecord.Total

WAIT "Hit enter to continue..."

* Note that the invoice hasn't been saved yet.

*ON ERROR  && Restore system error handler

*!*	* Print out the error.
*!*	PROCEDURE errhand
*!*	   = AERROR(aErrorArray)  && Data from most recent error

*!*	   ?
*!*	   ? "*************** Error ****************"
*!*	   ? 'The error provided the following information'  && Display message
*!*	   FOR n = 1 TO 7  && Display all elements of the array
*!*	      ? aErrorArray(n)
*!*	   ENDFOR
*!*	ENDPROC

You can see that I have since commented out the error handler that uses AError().

F.Y.I. the database is the same database in both test environments. It's on the server, but is referenced through a mapped drive on the development machine. So, it's exactly the same data.

The question remains for me: How can this work outside of VFP on my development machine, but the same test program fails at AddPromotion() on the server.
 
I'm more interested in what's happening in the method throwing the error. In that method, you need to add some logging to record what it's doing. The logging method should write those messages to a text file on the server. You can then look at that file and see what it's doing.

Craig Berntson
MCSD, Visual C# MVP,
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top