BUG: Operating System Regional Settings Effect VFP COM ObjectsID: Q195261
|
When you call a method of a COM object written in Visual FoxPro 6.0, the following error might appear:
OLE error code 0x8002801d: Library not registered.
The Visual FoxPro COM object was built on an operating system that uses a different language ID (LCID) regional setting than the one that the COM object is being instantiated on.
Do one of the following to resolve this problem:
** Begin program code **
********************************************************
* Program: Tag_TLB_LCID
*
* Param: TLB_FileName [,LCID]
*
* Note: The first param can have any extension (for example, DLL).
*
* This utility tags a Visual FoxPro-created TLB file with the LCID
* specified or with LANG_NEUTRAL by default. This allows
* COM DLLs created with Visual FoxPro 6.0 to be distributed to
* operating systems that have different Language or Dialect
* (sublanguage) settings. This has only been tested on
* TLBs created with Visual FoxPro 6.0, and is not guaranteed to
* work correctly on all TLBs created with Visual FoxPro 6.0.
*
* The TLB file format could not be completely reverse-
* engineered, so you must look for a marker that you believe
* will always point you to the typelib description field.
* the LCID appears nine bytes after that.
*
* The original TLB file is backed up, with _ORIG_LCID
* tacked on to the name (for example, Test_ORIG_LCID.TLB)
*
* If it is successful, the procedure returns ".T.".
*
* For information on what to pass as an LCID for a particular
* region, look at the #DEFINEs in FoxPro.H.
*
***********************************************************
* Localizable strings:
#DEFINE D_GETFILE_CAPTION_LOC "Select a Type Library to modify"
#DEFINE D_NO_TLB_LOC "Could not open Type Library, ;
or Type Library ;is empty."
#DEFINE D_ERROR_PARSING_TLB_LOC "Typelib has no description? ;
Error parsing TLB."
#DEFINE D_CANNOT_FIND_FILE_LOC "Cannot find file '%s'."
#DEFINE D_BACKUP_FILENAME_POSTFIX "_ORIG_LCID.TLB"
* Non-localizable definitions
#DEFINE LANG_NEUTRAL 0x0000
#DEFINE D_OBJECT_DEF_MARKER "*\Rffff*#"
*****************************************
* Code begins
*****************************************
LPARAMETERS cDLLName, nLCID
LOCAL cLCID, cTLBContents, nTypeLibDesc, nDescLength, nLangIDLocation
LOCAL cOldSafety, cTargetFileName, nLastMarker, nOffset
* If no filename passed, prompt for a file.
IF PCOUNT() < 1
cDLLName = "*.DLL"
cDLLName = GETFILE("DLL,TLB", D_GETFILE_CAPTION_LOC)
IF EMPTY(cDLLName)
* User pressed cancel.
RETURN .f.
ENDIF
ENDIF
* If no LCID passed, assume LANG_NEUTRAL (0x0000).
IF PCOUNT() < 2
nLCID = LANG_NEUTRAL
ENDIF
* Convert it to a two-byte string, with the low byte first.
cLCID = CHR(BITAND(nLCID, 0xFF)) + ;
CHR(BITRSHIFT(BITAND(nLCID, 0xFF00),8))
* If not a TLB file, replace the extension with .tlb.
IF ! UPPER(RIGHT(ALLTR(cDLLName), 4)) = ".TLB"
cDLLName = AddBS(JustPath(cDLLName)) + JustStem(cDllName) + ".TLB"
IF NOT FILE(cDLLName)
Messagebox(STRTRAN(D_CANNOT_FIND_FILE_LOC, "%s", cDllName))
RETURN .F.
ENDIF
ENDIF
* TLBs are never huge, so just use FILETOSTR instead of FOPEN, and so
* forth.
cTLBContents = FILETOSTR(cDllName)
IF TYPE("cTLBContents") # "C" OR EMPTY(cTLBContents)
Messagebox(D_NO_TLB_LOC)
RETURN .F.
ENDIF
* Find TypeLib Description, which is just past the last
* occurrence of *\Rffff*#. Actually, if there are more than 15
* COM objects in the DLL, the number (written in ascii) that
* comes just past the # can be more than one digit,
* so we need to count from the eszet (0xDF) that comes just after.
nLastMarker = RAT(D_OBJECT_DEF_MARKER, cTLBContents)
nOffset = AT(CHR(0xDF), SUBSTR(cTLBContents, nLastMarker, 20))
nTypeLibDesc = nLastMarker + nOffset + 97
* Assume description will not be more that 255 bytes, so only read one
* byte of length field.
nDescLength = ASC(SUBSTR(cTLBContents, nTypeLibDesc, 1))
IF nDescLength = 0
Messagebox(D_ERROR_PARSING_TLB_LOC)
RETURN .F.
ENDIF
* Now that you have the description length, you know exactly
* where the LCID is written.
nLangIDLocation = nTypeLibDesc + nDescLength + 10
* Back up original file.
cOldSafety = SET("SAFETY")
SET SAFETY OFF
cTargetFileName = ADDBS(JUSTPATH(cDllName)) + JUSTSTEM(cDLLNAME) +;
D_BACKUP_FILENAME_POSTFIX
ERASE (cTargetFileName)
RENAME (cDLLName) TO (cTargetFileName)
* Now, write your file.
STRTOFILE(LEFT(cTLBContents, nLangIDLocation - 1) + cLCID + ;
SUBSTR(cTLBContents, nLangIDLocation + 2), cDLLName)
* Restore environment settings.
SET SAFETY &cOldSafety
RETURN .T.
** End program code **
After you build a Visual FoxPro COM object, you can call the Tag_TLB_LCID
program to stamp the type library with the language neutral LCID using the
following syntax:
DO Tag_TLB_LCID WITH "<your dll filename>"
This functionality could be implemented using a project hook class. Use
the AfterBuild event of the project hook class to make the sample program
call.
Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article.
ox=NewObject("foxsrch.gopher") ox.updatede
OLE error code 0x8002801d: Library not registered.
Additional query words:
Keywords : kbcode kbCOMt kbVFp600bug
Version :
Platform :
Issue type : kbbug
Last Reviewed: August 5, 1999