April 28, 2024, 12:00:43 PM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Conversion from VB6 to IWBASIC

Started by pistol350, October 20, 2010, 09:13:40 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

pistol350

Hello all,
I'm about to develop softwares for the company where i'm currently working and i would like to use IWBASIC for that purpose.
One of the projects was started with VB6 and it involves using Activex and now i'm trying to convert it to IWBASIC's syntax.
I don't know much about VB6 and even less about it's syntax so now i'm trying to find out if i can reach my goal using my favourite programming language.

I've found quite a lot threads in the forums where it is said that IWBASIC should do the job so could anyone helps to convert the sample code below?
Thanks


'=========================================================================
Public Function OnFileSaveAfter(ByVal lCallParamsBlock As Long) As Boolean
'=========================================================================
oAppli As Object
oScene As Object
lSessionId As Long
bOk As Boolean
lNbObjects As Long

Set oAppli = CreateObject("test.Appli")
Set oScene = CreateObject("test.Scene")

lSessionId = oAppli.StartSessionFromCallParams(lCallParamsBlock)

lNbObjects = oScene.SceneGetObjectsNb(lSessionId)
MsgBox "Number of items in the scene : " & lNbObjects

bOk = oAppli.EndSession(lSessionId)

Set oAppli = Nothing
Set oScene = Nothing

OnFileSaveAfter = True
End Function
Regards,

Peter B.

WayneA

Knowing sapero he'll just answer this off the top of his head.. For me I need something to play with to figure it out. Is the activex control in question internal or is it one that I could download somewhere along with it's documentation and try to get a working example going for you?

If its the former, I suggest you look into CreateComObject and CallObjectMethod. These are the closest analogues we have to the way VB instantiates objects.

Theres also the COM framework which personally I've never beenable to use correctly.

Simple example I have in my example folder (I think this is from one of the example sources that ships with IWB)

Sub Speak(words As String),Int
IDispatch speech
speech=CreateComObject("Sapi.SpVoice","")
If speech<=0 Then
Return False
EndIf
CallObjectMethod(speech,".Speak(%s)",words)
speech->Release()
Return True
EndSub
99 little bugs in the code,
99 bugs in the code,
Fix one bug,
Compile again,
104 little bugs in the code...

All code I post is in the public domain.

pistol350

Hello Wayne!

Unfortunately the activeX control is internal and not open to all which does not help...
By the way, your suggestions should help a lot.
I'm quite new to Activex and did not think of using COM interface.
Well for the time being i'll try using all the COM interface examples that I can find around.

Thanks again!  :)
Regards,

Peter B.

pistol350

Hi all!
As i said previously, i'm new to COM INTERFACE programming and i am having a hard time converting a few lines from VB6 to IWBASIC.

From the sample above :
lSessionId = oAppli.StartSessionFromCallParams(lCallParamsBlock)

lSessionId is an integer returned by the method called
oAppli is the object created
StartSessionFromCallParams(lCallParamsBlock) is the method plus its parameter (an integer) called by our object

So what should we have in IWBASIC ?
Maybe :
CallObjectMethod(oAppli,".StartSessionFromCallParams(%d)",lCallParamsBlock)

Then How can I get the lSessionId returned by my method ?
Maybe with GetComProperty()
Then how can i do it ?
Any suggestions please  ;D ?
Regards,

Peter B.

LarryMc

Hey Pete,

I'd help but I'm lost when it comes to the COM/ActiveX stuff.

Maybe someone like Sapero can come up with a streamlined standard process/designer/editor for creating/using that stuff.
Hint, Hint  ;) ;) ;)

LarryMc
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

sapero

Is this a "KitchenDraw SDK" ? (google:StartSessionFromCallParams)

pistol350

Hello Sapero!
It is indeed about the kitchen Draw SDK.
I really thought that the SDK docs were not open but just googling "StartSessionFromCallParams" leads straight to them.
Quite funny!!  :)

By the way, i have the main dll (kdsdk.dll) where all the objects reside.
I've created an import library from it (kdsdk.lib) that i $USE in my projects
If you need more resources just let me know.

@Larry,
I know  you would be one of the first to help if you had a solution  ;)
Thanks anyway.
Regards,

Peter B.

sapero

I have a question: what is "lCallParamsBlock" ? It is not defined in KD examples, nor in the type library.
Ok, found it - it is a parameter in the OnFileSaveAfter function.

Attached is my example and three headers: for Aurora, EBasic, and for the new, pending IWBasic compiler. The headers are extracted from Kdsdk.dll type library.
Kd50e_guids.lib contains all the referenced guids, and you can copy it to /libs directory and "$use" it, or just add this file to your KD projects.

My conversion has three blocks:
1. Switch to a sanbox for temporary usage/dll registration (will be idle on your machine).
2. Create the first object. On failure, register the ocx and try to create the object again
3. Create the second object, and execute the methods form your example code.

lSessionId = oAppli.StartSessionFromCallParams(lCallParamsBlock)
This will be converted to
oAppli->StartSessionFromCallParams(lCallParamsBlock, &lSessionId)

My example uses hardcoded paths, so take care!
The import library you created for Kdsdk.dll is no use for you, it is exporting 4 OCX-common functions (register+unregister+unload+createObject)

pistol350

Thank you so much Sapero!  ;D
I'm about to give it a try and study all the work that you've done.
I'll probably come back to you with a few questions though.
Regards,

Peter B.

sapero

This is not a problem. I have found a bug in my code:
oScene->SceneGetObjectsNb(oAppli, &lNbObjects)
Instead oAppli, there should be lSessionId (or better &lSessionId). I have no idea why all the arguments were defined as pointers. In VB this is working like a reference to all parameters.
virtual SceneGetObjectsNb(long* SessionId, long* ppRetval)

pistol350

To sapero,

Here are the GUIDs to be converted to .lib file
Thanks again.
Regards,

Peter B.

sapero

OK, attached is the extra library for your KD version. Your include file does not define class identifiers (CLSID), so I have just duplicated the identifiers from my previous attachment.

What I really used from your header:
(optional) Library GUID: {A7952C70-4EA7-4F3F-908A-AC77A140C842} -> extern _LIBID_KDSDK as GUID

// Interface name = _Catalog
// IID = {1D368938-4BA8-4DC8-90D7-BF72A21B9F3A} -> extern _IID__Catalog as GUID

// Interface name = _Scene
// IID = {FA9CDF1F-0939-4EEB-A405-0388E188BCE9} -> extern _IID__Scene as GUID

// Interface name = _Appli
// IID = {1D6D5300-5DA6-4148-B349-7F7705D6F815} -> extern _IID__Appli as GUID

// Interface name = _Dico
// IID = {5DAA1897-E5EB-4C4B-842D-86CB7931D1ED} -> extern _IID__Dico as GUID

+ all class id's (clsids are missing)

sapero

November 08, 2010, 12:52:38 PM #12 Last Edit: November 09, 2010, 12:14:32 AM by sapero
OK, done, it is working now!
In classfactory::CreateInstance instead the dispatch based, I have returned another factory class.
Now the console window opens and I see the debug mode prints. Right after you start KD, the console will open and print "DllGetClassObject". After you click New,  the console will print "OnAppStartAfter".

Use the CKDplugStuff class to manage the On** methods. Three dummy methods are there. After modifying CKDplugStuff (new/deleted/shuffled methods) the .IDL file must be modified and recompilled also, to reflect the new order of methods in CKDplugStuff class.

The part of .IDL file to update:
interface IKDplugStuff : IDispatch {
[id(0x60030000)]
HRESULT _stdcall OnFileNewBefore([in] long lCallParamsBlock, [out, retval] VARIANT_BOOL *success);
HRESULT _stdcall OnFileSaveAfter([in] long lCallParamsBlock, [out, retval] VARIANT_BOOL *success);
HRESULT _stdcall OnAppStartAfter([in] long lCallParamsBlock, [out, retval] VARIANT_BOOL *success);
};


Command line for the compiler:
@call "C:\Program Files\Microsoft Platform SDK\SetEnv.Cmd"
midl /newtlb KDplug.idl


And sorry for the "zerodog" word used in my previous uploads :)

NOTE: When it happens that KitchenDraw stops responding after clicking Save, remove the code part with SceneGetObjectsNb from CKDplugStuff::OnFileSaveAfter.

pistol350

Thank you Sapero for this great and huge work you are doing to get all that stuff working.

I appreciate the effort
:)
Regards,

Peter B.

sapero

November 09, 2010, 05:23:55 AM #14 Last Edit: November 09, 2010, 04:00:33 PM by sapero
Ok, this is the tiny typelib maker. All informations it needs, are read from an ini file (ini file name must be same as the exe: abc.exe + abc.ini).
Compile for console.

$include "shlwapi.inc"
$include "oleauto.inc"
$include "stdio.inc"

GUID _LIBID_KDplugStuff
GUID _IID_IKDplugStuff
GUID _CLSID_KDplugStuff

ICreateTypeLib  g_cTypeLib
ITypeLib        g_stdole2Lib
ITypeInfo       g_oleDispatch
ICreateTypeInfo g_tiInterface
ICreateTypeInfo g_tiClass
HREFTYPE        g_refType

iwstring szBuffer[256]

GetSettingsString(L"ClassGuid", szBuffer, 256)
Check(CLSIDFromString(szBuffer, _CLSID_KDplugStuff), "ClassGuid")
print "ClassGuid            ", szBuffer

GetSettingsString(L"InterfaceGuid", szBuffer, 256)
Check(CLSIDFromString(szBuffer, _IID_IKDplugStuff), "InterfaceGuid")
print "InterfaceGuid        ", szBuffer

GetSettingsString(L"TypelibGuid", szBuffer, 256)
Check(CLSIDFromString(szBuffer, _LIBID_KDplugStuff), "TypelibGuid")
print "TypelibGuid          ", szBuffer




CoInitialize(0)

GetSettingsString(L"OutputFileName", szBuffer, 256)
print "OutputFileName       ", szBuffer
if (Check(CreateTypeLib(SYS_WIN32, szBuffer, &g_cTypeLib), "CreateTypeLib"))

if (Check(LoadRegTypeLib(_IID_StdOle, 2, 0, 0, &g_stdole2Lib), "LoadRegTypeLib"))

if (Check(g_stdole2Lib->GetTypeInfoOfGuid(_IID_IDispatch, &g_oleDispatch), "g_stdole2Lib::GetTypeInfoOfGuid"))
'
' initialize the typelib attributes
'
Check(g_cTypeLib->SetGuid(_LIBID_KDplugStuff), "g_cTypeLib::SetGuid")
GetSettingsString(L"TypelibName", szBuffer, 256)
print "TypelibName          ", szBuffer
Check(g_cTypeLib->SetName(szBuffer), "g_cTypeLib::SetName")
GetSettingsString(L"TypelibDescription", szBuffer, 256)
print "TypelibDescription   ", szBuffer
Check(g_cTypeLib->SetDocString(szBuffer), "g_cTypeLib::SetDocString")
Check(g_cTypeLib->SetVersion(1, 0), "g_cTypeLib::SetVersion")

'
' add IKDplugStuff interface
'
GetSettingsString(L"InterfaceName", szBuffer, 256)
print "InterfaceName        ", szBuffer
if (Check(g_cTypeLib->CreateTypeInfo(szBuffer, TKIND_INTERFACE, &g_tiInterface), "g_cTypeLib::CreateTypeInfo INTERFACE"))

Check(g_tiInterface->SetGuid(_IID_IKDplugStuff), "g_tiInterface::SetGuid")
GetSettingsString(L"InterfaceDescription", szBuffer, 256)
print "InterfaceDescription ", szBuffer
Check(g_tiInterface->SetDocString(szBuffer), "g_tiInterface::SetDocString")
Check(g_tiInterface->SetTypeFlags(TYPEFLAG_FDUAL | TYPEFLAG_FOLEAUTOMATION), "g_tiInterface::SetTypeFlags")

Check(g_tiInterface->AddRefTypeInfo(g_oleDispatch, &g_refType), "g_tiInterface::AddRefTypeInfo")
Check(g_tiInterface->AddImplType(0, g_refType), "g_tiInterface::AddImplType")
'
' add some methods
'
int methodIndex=0
iwstring text[32]
wsprintfW(text, L"method%d", methodIndex)
while (GetSettingsString(text, szBuffer, -256))
print "method               ", szBuffer
methodIndex++
wsprintfW(text, L"method%d", methodIndex)
AddMethod(szBuffer)
endwhile
'
' finalize the interface
'
Check(g_tiInterface->LayOut(), "g_tiInterface::LayOut")
g_tiInterface->Release()
endif
'
' add KDplugStuff coclass
'
GetSettingsString(L"CoClassName", szBuffer, 256)
print "CoClassName          ", szBuffer
if (Check(g_cTypeLib->CreateTypeInfo(szBuffer, TKIND_COCLASS, &g_tiClass), "g_cTypeLib::CreateTypeInfo COCLASS"))

Check(g_tiClass->SetGuid(_CLSID_KDplugStuff), "g_tiClass::SetGuid COCLASS")
GetSettingsString(L"CoClassDescription", szBuffer, 256)
print "CoClassDescription   ", szBuffer
Check(g_tiClass->SetDocString(szBuffer), "g_tiClass::SetDocString")
Check(g_tiClass->SetVersion(1, 0), "g_tiClass::SetVersion")
Check(g_tiClass->SetTypeFlags(TYPEFLAG_FCANCREATE), "g_tiClass::SetTypeFlags")
'
' insert IKDplugStuff interface to KDplugStuff coclass
'
ITypeLib pTypeLib
if (Check(g_cTypeLib->QueryInterface(_IID_ITypeLib, &pTypeLib), "g_cTypeLib::QueryInterface"))
ITypeInfo pTypeInfo
if (Check(pTypeLib->GetTypeInfoOfGuid(_IID_IKDplugStuff, &pTypeInfo), "pTypeLib::GetTypeInfoOfGuid IID_IKDplugStuff"))

Check(g_tiClass->AddRefTypeInfo(pTypeInfo, &g_refType), "g_tiClass::AddRefTypeInfo")
Check(g_tiClass->AddImplType(0, g_refType), "g_tiClass::AddImplType")
'
' mark IKDplugStuff interface as the default interface in this class
'
Check(g_tiClass->SetImplTypeFlags(0, IMPLTYPEFLAG_FDEFAULT), "g_tiClass::SetImplTypeFlags")
pTypeInfo->Release()
endif
pTypeLib->Release()
endif

Check(g_tiClass->LayOut(), "g_tiClass::LayOut")
g_tiClass->Release()
endif

g_oleDispatch->Release()
endif
g_stdole2Lib->Release()
endif

Check(g_cTypeLib->SaveAllChanges(), "g_cTypeLib::SaveAllChanges")
g_cTypeLib->Release()
endif
CoUninitialize()
end


sub GetSettingsString(wstring name, wstring buffer, int cch),BOOL
iwstring path[MAX_PATH]
' exe path
GetModuleFileNameW(0, &path, MAX_PATH)
' ini path
PathRenameExtensionW(path, L".ini")
buffer[0] = 0
GetPrivateProfileStringW(L"settings", name, NULL, buffer, ABS(cch), path)
if (!buffer[0])
if (cch<0) then return FALSE
_snwprintf(buffer, MAX_PATH, L"The '%s' value is missing in [settings] section in ini file", name)
MessageBoxW(0, buffer, 0, MB_ICONHAND)
end
endif
return TRUE
endsub


int %g_FunctionId = 0x60030000
int g_FunctionIndex

sub AddMethod(wstring name)
FUNCDESC fd
ELEMDESC myParams[2]
TYPEDESC tdBool
TYPEDESC tdescUser

ZeroMemory(&fd, len(fd))
ZeroMemory(&myParams, len(myParams))
ZeroMemory(&tdBool, len(tdBool))
ZeroMemory(&tdescUser, len(tdescUser))

tdBool.vt = VT_BOOL

myParams[0].tdesc.vt      = VT_I4
myParams[0].idldesc.wIDLFlags = IDLFLAG_FIN
myParams[1].tdesc.vt = VT_PTR
myParams[1].tdesc.lptdesc = &tdBool
myParams[1].idldesc.wIDLFlags = IDLFLAG_FOUT | IDLFLAG_FRETVAL

fd.memid             = g_FunctionId
fd.lprgelemdescParam = &myParams
fd.funckind          = FUNC_PUREVIRTUAL
fd.invkind           = INVOKE_FUNC
fd.callconv          = CC_STDCALL
fd.cParams           = 2 ' Count of total number of parameters
' return type of the function
fd.elemdescFunc.tdesc.vt = VT_HRESULT
fd.elemdescFunc.tdesc.lptdesc = &tdescUser


if (Check(g_tiInterface->AddFuncDesc(g_FunctionIndex, &fd), "g_tiInterface::AddFuncDesc"))
pointer names[3]
names[0] = name
names[1] = L"lCallParamsBlock"
names[2] = L"retval"
Check(g_tiInterface->SetFuncAndParamNames(g_FunctionIndex, &names, 3), "g_tiInterface::SetFuncAndParamNames")
'Check(g_tiInterface->LayOut(), "g_tiInterface::LayOut")
endif
g_FunctionId++
g_FunctionIndex++
endsub


sub Check(DWORD hr, string info),BOOL
if (FAILED(hr))
print " * Error 0x", HEX$(hr)
MESSAGEBOX 0, info + " failed 0x" + HEX$(hr), ""
endif
return SUCCEEDED(hr)
endsub



Example ini file:
[settings]
ClassGuid     ={64d82c8d-2776-4503-aadc-f4ab90be82a7}
InterfaceGuid ={b3bd8884-c981-4445-a2b2-f72db9116ebb}
TypelibGuid   ={223A17F8-255B-431A-9717-477714D2F5C0}

OutputFileName     =KDplugTest.tlb
TypelibName        =KDplugStuff
TypelibDescription =KDplug plugin for KitchenDraw

InterfaceName        =IKDplugStuff
InterfaceDescription =IKDplugStuff Interface

CoClassName        =KDplugStuff
CoClassDescription =KDplugStuff class

method0 =OnFileNewBefore
method1 =OnFileSaveAfter
method2 =OnAppStartAfter

[howto]
info=if you have only one method, define only method0


If it will not compile, update your headers from Newest IWB SDK pak, or (headers only): http://x7.to/36n2en or http://www.sendspace.com/file/88itmo - I have updated some of them, fixed some smal bugs, removed empty spaces.

EDIT: added missing parameter to _snwprintf.

pistol350

Indeed  it does not.
and i am having a hard time trying to download the file from the link provide ^^
Regards,

Peter B.

Bill-Bo

Sapero,

The http://x7.to/36n2en for your header file just runs me in circles,
and I am not able to download the header file. Sure would appreciate
a link similar to the one for your inc file.

Your a DAMN!!! good programmer. Keep up the great work.

Bill-Bo

pistol350

Hi Bill-Bo!
See the mirror link on the right of the x7 link.
Regards,

Peter B.

sapero

I was able to download from x7, this free service like megaupload and netload, offers the best bandwidth for free users - up to 600 KB/s or even more.

pistol350

Then give us your secret  ;D
I've really tried a lot with no success before giving up and try to the sendspace link.
Regards,

Peter B.

Bill-Bo

Ran the mirror and was able to download the headers.

Thanks.

Sir Sapero, will the July EBasic headers install and
work with the new IWBasic 1.8? The install still
looks for the EBDev directory. I still have 1.737
installed.

Thanks, again.

Bill-Bo

sapero

November 09, 2010, 10:22:44 AM #21 Last Edit: November 09, 2010, 10:42:54 AM by sapero
It will be working with 1.8. The current headers-installer does not handle the new registry settings, but you can install the headers to any directory you wish, for example to your 1.8 root directory.
I will update the installer for IWBasic.

I have modified the typelib maker a bit. In addition you can (you must) specify major and minor versions for the typelib, interface and coclass.
A method can have description. To add the description, put a space and the description after method name:
[TypeLib]
Guid        ={223A17F8-255B-431A-9717-477714D2F5C0}
FileName    =KDplug.tlb
Name        =KDplugStuff
Description =KDplug plugin for KitchenDraw
Major       =1
Minor       =0

[Interface]
Guid        ={b3bd8884-c981-4445-a2b2-f72db9116ebb}
Name        =IKDplugStuff
Description =IKDplugStuff Interface
Major       =1
Minor       =0

[CoClass]
Guid        ={64d82c8d-2776-4503-aadc-f4ab90be82a7}
Name        =KDplugStuff
Description =KDplugStuff class
Major       =1
Minor       =0

[Methods]
method0 =OnFileNewBefore HERE, after space begins method description
method1 =OnFileSaveAfter
method2 =OnAppStartAfter Fired after application start


$include "shlwapi.inc"
$include "oleauto.inc"
$include "stdio.inc"

GUID _LIBID_FromFile
GUID _IID_FromFile
GUID _CLSID_FromFile

ICreateTypeLib  g_cTypeLib
ITypeLib        g_stdole2Lib
ITypeInfo       g_oleDispatch
ICreateTypeInfo g_tiInterface
ICreateTypeInfo g_tiClass
HREFTYPE        g_refType
int major, minor
iwstring g_szBuffer[256]
iwstring g_szIniFilePath[256]

' ini path
GetModuleFileNameW(0, g_szIniFilePath, MAX_PATH)
PathRenameExtensionW(g_szIniFilePath, L".ini")

GetSettingsString(L"CoClass", L"Guid", g_szBuffer, 256)
Check(CLSIDFromString(g_szBuffer, _CLSID_FromFile), "ClassGuid")
print "ClassGuid            ", g_szBuffer

GetSettingsString(L"Interface", L"Guid", g_szBuffer, 256)
Check(CLSIDFromString(g_szBuffer, _IID_FromFile), "InterfaceGuid")
print "InterfaceGuid        ", g_szBuffer

GetSettingsString(L"TypeLib", L"Guid", g_szBuffer, 256)
Check(CLSIDFromString(g_szBuffer, _LIBID_FromFile), "TypeLibGuid")
print "TypeLibGuid          ", g_szBuffer




CoInitialize(0)

GetSettingsString(L"TypeLib", L"FileName", g_szBuffer, 256)
print "OutputFileName       ", g_szBuffer
if (Check(CreateTypeLib(SYS_WIN32, g_szBuffer, &g_cTypeLib), "CreateTypeLib"))

if (Check(LoadRegTypeLib(_IID_StdOle, 2, 0, 0, &g_stdole2Lib), "LoadRegTypeLib"))

if (Check(g_stdole2Lib->GetTypeInfoOfGuid(_IID_IDispatch, &g_oleDispatch), "g_stdole2Lib::GetTypeInfoOfGuid"))
'
' initialize the typelib attributes
'
Check(g_cTypeLib->SetGuid(_LIBID_FromFile), "g_cTypeLib::SetGuid")
GetSettingsString(L"TypeLib", L"Name", g_szBuffer, 256)
print "TypeLibName          ", g_szBuffer
Check(g_cTypeLib->SetName(g_szBuffer), "g_cTypeLib::SetName")
GetSettingsString(L"TypeLib", L"Description", g_szBuffer, 256)
print "TypeLibDescription   ", g_szBuffer
Check(g_cTypeLib->SetDocString(g_szBuffer), "g_cTypeLib::SetDocString")
GetSettingsInt(L"TypeLib", L"Major", &major)
print "major                ", major
GetSettingsInt(L"TypeLib", L"Minor", &minor)
print "minor                ", minor
Check(g_cTypeLib->SetVersion(major, minor), "g_cTypeLib::SetVersion")

'
' add IKDplugStuff interface
'
GetSettingsString(L"Interface", L"Name", g_szBuffer, 256)
print "InterfaceName        ", g_szBuffer
if (Check(g_cTypeLib->CreateTypeInfo(g_szBuffer, TKIND_INTERFACE, &g_tiInterface), "g_cTypeLib::CreateTypeInfo INTERFACE"))

Check(g_tiInterface->SetGuid(_IID_FromFile), "g_tiInterface::SetGuid")
GetSettingsString(L"Interface", L"Description", g_szBuffer, 256)
print "InterfaceDescription ", g_szBuffer
Check(g_tiInterface->SetDocString(g_szBuffer), "g_tiInterface::SetDocString")
Check(g_tiInterface->SetTypeFlags(TYPEFLAG_FDUAL | TYPEFLAG_FOLEAUTOMATION), "g_tiInterface::SetTypeFlags")

Check(g_tiInterface->AddRefTypeInfo(g_oleDispatch, &g_refType), "g_tiInterface::AddRefTypeInfo")
Check(g_tiInterface->AddImplType(0, g_refType), "g_tiInterface::AddImplType")
GetSettingsInt(L"Interface", L"Major", &major)
print "major                ", major
GetSettingsInt(L"Interface", L"Minor", &minor)
print "minor                ", minor
Check(g_tiInterface->SetVersion(major, minor), "g_tiClass::SetVersion")
'
' add some methods
'
int methodIndex
iwstring text[32]
for methodIndex=0 to 0x7FFFFFFF
wsprintfW(text, L"method%d", methodIndex)
if (!GetSettingsString(L"Methods", text, g_szBuffer, -256)) then breakfor
print "method               ", g_szBuffer
AddMethod(g_szBuffer)
next methodIndex
'
' finalize the interface
'
Check(g_tiInterface->LayOut(), "g_tiInterface::LayOut")
g_tiInterface->Release()
endif
'
' add KDplugStuff coclass
'
GetSettingsString(L"CoClass", L"Name", g_szBuffer, 256)
print "CoClassName          ", g_szBuffer
if (Check(g_cTypeLib->CreateTypeInfo(g_szBuffer, TKIND_COCLASS, &g_tiClass), "g_cTypeLib::CreateTypeInfo COCLASS"))

Check(g_tiClass->SetGuid(_CLSID_FromFile), "g_tiClass::SetGuid COCLASS")
GetSettingsString(L"CoClass", L"Description", g_szBuffer, 256)
print "CoClassDescription   ", g_szBuffer
Check(g_tiClass->SetDocString(g_szBuffer), "g_tiClass::SetDocString")
GetSettingsInt(L"CoClass", L"Major", &major)
print "major                ", major
GetSettingsInt(L"CoClass", L"Minor", &minor)
print "minor                ", minor
Check(g_tiClass->SetVersion(major, minor), "g_tiClass::SetVersion")
Check(g_tiClass->SetTypeFlags(TYPEFLAG_FCANCREATE), "g_tiClass::SetTypeFlags")
'
' insert IKDplugStuff interface to KDplugStuff coclass
'
ITypeLib pTypeLib
if (Check(g_cTypeLib->QueryInterface(_IID_ITypeLib, &pTypeLib), "g_cTypeLib::QueryInterface"))
ITypeInfo pTypeInfo
if (Check(pTypeLib->GetTypeInfoOfGuid(_IID_FromFile, &pTypeInfo), "pTypeLib::GetTypeInfoOfGuid IID_IKDplugStuff"))

Check(g_tiClass->AddRefTypeInfo(pTypeInfo, &g_refType), "g_tiClass::AddRefTypeInfo")
Check(g_tiClass->AddImplType(0, g_refType), "g_tiClass::AddImplType")
'
' mark IKDplugStuff interface as the default interface in this class
'
Check(g_tiClass->SetImplTypeFlags(0, IMPLTYPEFLAG_FDEFAULT), "g_tiClass::SetImplTypeFlags")
pTypeInfo->Release()
endif
pTypeLib->Release()
endif

Check(g_tiClass->LayOut(), "g_tiClass::LayOut")
g_tiClass->Release()
endif

g_oleDispatch->Release()
endif
g_stdole2Lib->Release()
endif

Check(g_cTypeLib->SaveAllChanges(), "g_cTypeLib::SaveAllChanges")
g_cTypeLib->Release()
endif
CoUninitialize()
end


sub GetSettingsString(wstring section, wstring name, wstring buffer, int cch),BOOL
buffer[0] = 0
GetPrivateProfileStringW(section, name, NULL, buffer, ABS(cch), g_szIniFilePath)
if (!buffer[0])
if (cch<0) then return FALSE
$ifdef __IWVER__
_snwprintf(buffer, cch, L"The '%s' value is missing in [%s] section in %s", name, section, PathFindFileNameW(g_szIniFilePath))
$else
_snwprintf(buffer, cch, L"The '%s' value is missing in [%s] section in %s", name, section, 0+PathFindFileNameW(g_szIniFilePath))
$endif
MessageBoxW(0, buffer, 0, MB_ICONHAND)
end
endif
return TRUE
endsub


sub GetSettingsInt(wstring section, wstring name, pointer pValue),BOOL
iwstring buffer[MAX_PATH]
*<int>pValue = GetPrivateProfileIntW(section, name, -1, g_szIniFilePath)
if (*<int>pValue = -1)
$ifdef __IWVER__
_snwprintf(&buffer, MAX_PATH, L"The '%s' integer is missing from [%s] section in %s", name, section, PathFindFileNameW(g_szIniFilePath))
$else
_snwprintf(&buffer, MAX_PATH, L"The '%s' integer is missing from [%s] section in %s", name, section, 0+PathFindFileNameW(g_szIniFilePath))
$endif
MessageBoxW(0, buffer, 0, MB_ICONHAND)
end
endif
return TRUE
endsub


int %g_FunctionId = 0x60030000
int g_FunctionIndex

sub AddMethod(wstring name)
FUNCDESC fd
ELEMDESC myParams[2]
TYPEDESC tdBool
TYPEDESC tdescUser

pointer pDescription = wcsstr(name, L" ")
if (pDescription)
*<WCHAR>pDescription = 0
pDescription += len(WCHAR)
endif

ZeroMemory(&fd, len(fd))
ZeroMemory(&myParams, len(myParams))
ZeroMemory(&tdBool, len(tdBool))
ZeroMemory(&tdescUser, len(tdescUser))

tdBool.vt = VT_BOOL

myParams[0].tdesc.vt          = VT_I4
myParams[0].idldesc.wIDLFlags = IDLFLAG_FIN
myParams[1].tdesc.vt          = VT_PTR
myParams[1].tdesc.lptdesc     = &tdBool
myParams[1].idldesc.wIDLFlags = IDLFLAG_FOUT | IDLFLAG_FRETVAL

fd.memid             = g_FunctionId
fd.lprgelemdescParam = &myParams
fd.funckind          = FUNC_PUREVIRTUAL
fd.invkind           = INVOKE_FUNC
fd.callconv          = CC_STDCALL
fd.cParams           = 2
' return type of the function
fd.elemdescFunc.tdesc.vt = VT_HRESULT
fd.elemdescFunc.tdesc.lptdesc = &tdescUser

if (Check(g_tiInterface->AddFuncDesc(g_FunctionIndex, &fd), "g_tiInterface::AddFuncDesc"))
pointer names[3]
names[0] = name
names[1] = L"lCallParamsBlock"
names[2] = L"retval"
Check(g_tiInterface->SetFuncAndParamNames(g_FunctionIndex, &names, 3), "g_tiInterface::SetFuncAndParamNames")
if (pDescription)
print "Description          ", *<wstring>pDescription
Check(g_tiInterface->SetFuncDocString(g_FunctionIndex, pDescription), "g_tiInterface::SetFuncDocString")
endif
endif
g_FunctionId++
g_FunctionIndex++
endsub


sub Check(DWORD hr, string info),BOOL
if (FAILED(hr))
print " * Error 0x", HEX$(hr)
MessageBoxA(0, info + " failed 0x" + HEX$(hr))
endif
return SUCCEEDED(hr)
endsub


Yet another note: if you replace CreateTypeLib with CreateTypeLib2, the format of the generated .tlb file will be newer/current (with MSFT tag), and there will be embedded just "stdole2.tlb", instead the full path to your /system32.
CreateTypeLib uses SLTG tag.