URL Monikers

Has anyone got a clue how to write an URL Moniker?
I am trying to use the Intenet Explorer to display HTML files that I pull out of a OLE2 structured storage file. Microsoft does s.th very similar in their Infoviewer 5 (comes with the MSDN): If you have the MSDN installed an type something like
mk:@ivt:activex/start.htm
IE will display the file start.htm from the knowledgebase file activex.ivt.
I already have found out that "ivt" in the above URL is registered in the registry and seems to be an URL Moniker. And from the MSDN I found out that I need to write an URL Moniker server.
Before I waste my time re-inventing the wheel: has somebody out there already written one?
Best regards,
Freter
LVL 2
freterAsked:
Who is Participating?
 
d003303Connect With a Mentor Commented:
OK, here we go. This moniker class does a simple parsing of the URL in TMyCustomMoniker.IParseDisplayNameParseDisplayName, transfers the requested file in TMyCustomMoniker.BindToStorage. I left in the debug stuff for tracing the monikers state.
Here's the unit and project, below are the registry keys to set.

// BOC //
unit _MyMoniker;

interface

uses
  Windows, Classes, ComObj, ActiveX;

const
   CLSID_MyCustomMoniker: TGUID = (
    D1:$556F12A1; D2:$DE94; D3:$11D1; D4:($B4, $EA, $00, $00, $E8, $2D, $8A, $65));
   Str_CLSID_MyCustomMoniker = '{556F12A1-DE94-11D1-B4EA-0000E82D8A65}';

   CLSID_NULL: TGUID = (D1:0; D2:0; D3:0; D4:(0, 0, 0, 0, 0, 0, 0, 0));

const
  IsDebug = false;

  OutStr = '<HTML>An error occured while parsing the URL<BR><B>%s</B><BR>Request URL was %s<BR></HTML>';

  FileSystemBase = 'c:';

type

  TMyCustomMoniker = class(TComObject, IParseDisplayName, IMoniker)
  private
    FOutStr,
    FErrorStr,
    FFileName,
    FRequestURL : string;
    FOLEOutStr  : POLEStr;
    FHash       : Longint;
  protected
    // IUnknown interface
    function ObjAddRef: Integer; override; stdcall;
    function ObjQueryInterface(const IID: TGUID; out Obj): Integer; override; stdcall;
    function ObjRelease: Integer; override; stdcall;
    // IParseDisplayName interface
    function IParseDisplayName.ParseDisplayName = IParseDisplayNameParseDisplayName;
    function IParseDisplayNameParseDisplayName(const bc: IBindCtx; pszDisplayName: POleStr;
      out chEaten: Longint; out mkOut: IMoniker): HResult; stdcall;
    // IPersist interface
    function GetClassID(out classID: TCLSID): HResult; stdcall;
    // IPersistStream interface
    function IsDirty: HResult; stdcall;
    function Load(const stm: IStream): HResult; stdcall;
    function Save(const stm: IStream; fClearDirty: BOOL): HResult; stdcall;
    function GetSizeMax(out cbSize: Largeint): HResult; stdcall;
    // IMoniker interface
    function BindToObject(const bc: IBindCtx; const mkToLeft: IMoniker;
      const iidResult: TIID; out vResult): HResult; stdcall;
    function BindToStorage(const bc: IBindCtx; const mkToLeft: IMoniker;
      const iid: TIID; out vObj): HResult; stdcall;
    function Reduce(const bc: IBindCtx; dwReduceHowFar: Longint;
      mkToLeft: PIMoniker; out mkReduced: IMoniker): HResult; stdcall;
    function ComposeWith(const mkRight: IMoniker; fOnlyIfNotGeneric: BOOL;
      out mkComposite: IMoniker): HResult; stdcall;
    function Enum(fForward: BOOL; out enumMoniker: IEnumMoniker): HResult;
      stdcall;
    function IsEqual(const mkOtherMoniker: IMoniker): HResult; stdcall;
    function Hash(out dwHash: Longint): HResult; stdcall;
    function IsRunning(const bc: IBindCtx; const mkToLeft: IMoniker;
      const mkNewlyRunning: IMoniker): HResult; stdcall;
    function GetTimeOfLastChange(const bc: IBindCtx; const mkToLeft: IMoniker;
      out filetime: TFileTime): HResult; stdcall;
    function Inverse(out mk: IMoniker): HResult; stdcall;
    function CommonPrefixWith(const mkOther: IMoniker;
      out mkPrefix: IMoniker): HResult; stdcall;
    function RelativePathTo(const mkOther: IMoniker;
      out mkRelPath: IMoniker): HResult; stdcall;
    function GetDisplayName(const bc: IBindCtx; const mkToLeft: IMoniker;
      out pszDisplayName: POleStr): HResult; stdcall;
    function ParseDisplayName(const bc: IBindCtx; const mkToLeft: IMoniker;
      pszDisplayName: POleStr; out chEaten: Longint;
      out mkOut: IMoniker): HResult; stdcall;
    function IsSystemMoniker(out dwMksys: Longint): HResult; stdcall;
  end;

  TMyStream = class(TComObject, IStream)
  private
    FTheStream  : TMemoryStream;
    FStatStg    : TStatStg;
    Fmtime,
    Fctime,
    Fatime      : TFileTime;
  protected
    function Read(pv: Pointer; cb: Longint; pcbRead: PLongint): HResult;
      stdcall;
    function Write(pv: Pointer; cb: Longint; pcbWritten: PLongint): HResult;
      stdcall;
    function Seek(dlibMove: Largeint; dwOrigin: Longint;
      out libNewPosition: Largeint): HResult; stdcall;
    function SetSize(libNewSize: Largeint): HResult; stdcall;
    function CopyTo(stm: IStream; cb: Largeint; out cbRead: Largeint;
      out cbWritten: Largeint): HResult; stdcall;
    function Commit(grfCommitFlags: Longint): HResult; stdcall;
    function Revert: HResult; stdcall;
    function LockRegion(libOffset: Largeint; cb: Largeint;
      dwLockType: Longint): HResult; stdcall;
    function UnlockRegion(libOffset: Largeint; cb: Largeint;
      dwLockType: Longint): HResult; stdcall;
    function Stat(out statstg: TStatStg; grfStatFlag: Longint): HResult;
      stdcall;
    function Clone(out stm: IStream): HResult; stdcall;
  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

uses ComServ, SysUtils;

const
  DebugFile = 'c:\debug.txt';

var
  F : Text;

procedure WriteDebug(S : string);
begin
  if IsDebug then
   begin
     AssignFile(F, DebugFile);
     Append(F);
     writeln(F, FormatDateTime('dddd, mmmm d, yyyy', Date)
             +  FormatDateTime(' hh:mm:ss', Time) + ': ' + S);
     CloseFile(F);
   end;  
end;

////////////////////////////////////////////////////////////////////////////////

// IUnknown interface
function TMyCustomMoniker.ObjAddRef: Integer;
begin
  Result := inherited ObjAddRef;
  writedebug(Format('ObjAddRef Result %d', [Result]));
end;

function TMyCustomMoniker.ObjQueryInterface(const IID: TGUID; out Obj): Integer;
var StrBuf : POleStr;
begin
  StringFromCLSID(IID, StrBuf);
  writedebug(Format('ObjQueryInterface IID %s', [StrBuf]));
  Result := inherited ObjQueryInterface(IID, Obj);
end;

function TMyCustomMoniker.ObjRelease: Integer;
begin
  Result := inherited ObjRelease;
  writedebug(Format('ObjRelease Result %d', [Result]));
end;

// IParseDisplayName interface
function TMyCustomMoniker.IParseDisplayNameParseDisplayName(const bc: IBindCtx; pszDisplayName: POleStr;
                            out chEaten: Longint; out mkOut: IMoniker): HResult;
var Index : Integer;
begin
  writedebug(Format('IParseDisplayNameParseDisplayName %s', [pszDisplayName]));
  bc.RegisterObjectBound(Self);
  mkOut := Self;
  FErrorStr := '';
  FFileName := '';
  FRequestURL := WideCharToString(pszDisplayName);
  chEaten := Length(FRequestURL) * 2;
  // interpretation
  Index := Pos('/', FRequestURL);
  if Index <> 0
   then FFileName := FileSystemBase + Copy(FRequestURL, Index, Length(FRequestURL) - Index + 1)
   else FErrorStr := 'Invalid request';
  Result := S_OK;
end;

// IPersist interface
function TMyCustomMoniker.GetClassID(out classID: TCLSID): HResult;
begin
  writedebug('GetClassID');
  classID := CLSID_MyCustomMoniker;
  Result := S_OK;
end;

// IPersistStream interface
function TMyCustomMoniker.IsDirty: HResult;
begin
  writedebug('IsDirty');
  Result := S_FALSE;
end;

function TMyCustomMoniker.Load(const stm: IStream): HResult;
begin
  writedebug('Load');
  Result := E_FAIL;
end;

function TMyCustomMoniker.Save(const stm: IStream; fClearDirty: BOOL): HResult;
begin
  writedebug('Save');
  stm._AddRef;
  GetMem(FOLEOutStr, Length(FOutStr) * 2);
  try
    StringToWideChar(FOutStr, FOLEOutStr, Length(FOutStr) * 2);
    Result := stm.Write(FOLEOutStr, Length(FOutStr) * 2, nil);
  finally
    FreeMem(FOLEOutStr, Length(FOutStr) * 2);
    stm._Release;
  end;
end;

function TMyCustomMoniker.GetSizeMax(out cbSize: Largeint): HResult;
begin
  writedebug('GetSizeMax');
  cbSize := Length(FOutStr) * 2;
  Result := S_OK;
end;

// IMoniker interface
function TMyCustomMoniker.BindToObject(const bc: IBindCtx; const mkToLeft: IMoniker;
                                       const iidResult: TIID; out vResult): HResult;
var StrBuf : POleStr;
begin
  StringFromCLSID(iidResult, StrBuf);
  writedebug(Format('BindToObject iidResult %s', [StrBuf]));
  IMoniker(vResult) := Self;
  Result := S_OK;
end;

function TMyCustomMoniker.BindToStorage(const bc: IBindCtx; const mkToLeft: IMoniker;
                                        const iid: TIID; out vObj): HResult;
var StrBuf : POleStr;
    TmpStream : TMemoryStream;
    NewStream : TMyStream;
begin
  StringFromCLSID(iid, StrBuf);
  writedebug(Format('BindToStorage iidResult %s', [StrBuf]));
  IUnknown(vObj) := nil;
  Result := MK_E_NOSTORAGE;
  if mkToLeft = nil
   then writedebug('mkToLef = NULL');
  if IsEqualIID(iid, IStream) then
   begin
     NewStream := TMyStream.Create;
     if FFileName <> '' then
      begin
        TmpStream := TMemoryStream.Create;
        try
        try
          TmpStream.LoadFromFile(FFileName);
          NewStream.FTheStream.LoadFromStream(TmpStream);
        except
          FErrorStr := Format('File %s not found', [FFileName]);
        end;
        finally
          TmpStream.Free;
        end;
      end;
     if FErrorStr <> '' then
      begin
        FOutStr := Format(OutStr, [FErrorStr, FRequestURL]);
        NewStream.FTheStream.Write(Pointer(FOutStr)^, Length(FOutStr));
      end;
     NewStream.FTheStream.Seek(0, soFromBeginning);
     bc.RegisterObjectBound(NewStream);
     IStream(vObj) := NewStream;
     Result := S_OK;
   end;
end;

function TMyCustomMoniker.Reduce(const bc: IBindCtx; dwReduceHowFar: Longint;
                                 mkToLeft: PIMoniker; out mkReduced: IMoniker): HResult;
begin
  writedebug(Format('Reduce how far: %d', [dwReduceHowFar]));
  mkReduced := Self;
  Result := MK_S_REDUCED_TO_SELF;
end;

function TMyCustomMoniker.ComposeWith(const mkRight: IMoniker; fOnlyIfNotGeneric: BOOL;
                                      out mkComposite: IMoniker): HResult;
begin
  writedebug('ComposeWith');
  Result := E_UNEXPECTED;
end;

function TMyCustomMoniker.Enum(fForward: BOOL; out enumMoniker: IEnumMoniker): HResult;
begin
  writedebug('Enum');
  enumMoniker := nil;
  Result := S_OK;
end;

function TMyCustomMoniker.IsEqual(const mkOtherMoniker: IMoniker): HResult;
begin
  Result := S_FALSE;
  if mkOtherMoniker = IMoniker(Self)
   then Result := S_OK;
  writedebug(Format('IsEqual %d', [Result]));
end;

function TMyCustomMoniker.Hash(out dwHash: Longint): HResult;
begin
  writedebug(Format('Hash %d', [dwHash]));
  FHash := dwHash;
  Result := S_OK;
end;

function TMyCustomMoniker.IsRunning(const bc: IBindCtx; const mkToLeft: IMoniker;
                                    const mkNewlyRunning: IMoniker): HResult;
begin
  writedebug('IsRunning');
  Result := S_OK;
end;

function TMyCustomMoniker.GetTimeOfLastChange(const bc: IBindCtx; const mkToLeft: IMoniker;
                                              out filetime: TFileTime): HResult;
begin
  writedebug('GetTimeOfLastChange');
  filetime.dwLowDateTime := 0;
  filetime.dwHighDateTime := 0;
  Result := E_NOTIMPL;
end;

function TMyCustomMoniker.Inverse(out mk: IMoniker): HResult;
begin
  writedebug('Inverse');
  Result := E_NOTIMPL;
end;

function TMyCustomMoniker.CommonPrefixWith(const mkOther: IMoniker; out mkPrefix: IMoniker): HResult;
begin
  writedebug('CommonPrefixWith');
  Result := S_OK;
end;

function TMyCustomMoniker.RelativePathTo(const mkOther: IMoniker; out mkRelPath: IMoniker): HResult;
begin
  writedebug('RelativePathTo');
  mkRelPath := mkOther;
  Result := MK_S_HIM;
end;

function TMyCustomMoniker.GetDisplayName(const bc: IBindCtx; const mkToLeft: IMoniker;
                                         out pszDisplayName: POleStr): HResult;
begin
  writedebug('GetDisplayName');
  Result := E_NOTIMPL;
end;

function TMyCustomMoniker.ParseDisplayName(const bc: IBindCtx; const mkToLeft: IMoniker;
                                           pszDisplayName: POleStr; out chEaten: Longint;
                                           out mkOut: IMoniker): HResult;
begin
  writedebug(Format('ParseDisplayName %s', [pszDisplayName]));
  chEaten := Length(WideCharToString(pszDisplayName)) * 2;
  mkOut := Self;
  Result := S_OK;
end;

function TMyCustomMoniker.IsSystemMoniker(out dwMksys: Longint): HResult;
begin
  writedebug('IsSystemMoniker');
  dwMksys := MKSYS_NONE;
  Result := S_FALSE;
end;

////////////////////////////////////////////////////////////////////////////////

constructor TMyStream.Create;
begin
//  inherited Create;
  writedebug('Stream.Create');
  FTheStream := TMemoryStream.Create;
  GetSystemTimeAsFileTime(Fmtime);
  GetSystemTimeAsFileTime(Fctime);
  GetSystemTimeAsFileTime(Fatime);
end;

destructor TMyStream.Destroy;
begin
  writedebug('Stream.Destroy');
  FTheStream.Free;
end;

function TMyStream.Read(pv: Pointer; cb: Longint; pcbRead: PLongint): HResult;
var cbRead : LongInt;
begin
  writedebug('Stream.Read');
  Result := S_OK;
  try
    cbRead := FTheStream.Read(pv^, cb);
    if pcbRead <> nil
     then pcbRead^ := cbRead;
    if cbRead = 0
     then Result := S_FALSE
     else GetSystemTimeAsFileTime(Fatime);
  except
    Result := S_FALSE;
  end;
end;

function TMyStream.Write(pv: Pointer; cb: Longint; pcbWritten: PLongint): HResult;
var cbWritten : LongInt;
begin
  writedebug('Stream.Write');
  Result := S_OK;
  try
    cbWritten := FTheStream.Write(pv^, cb);
    if pcbWritten <> nil
     then pcbWritten^ := cbWritten;
    GetSystemTimeAsFileTime(Fatime);
    GetSystemTimeAsFileTime(Fmtime);
  except
    Result := STG_E_CANTSAVE;
  end;
end;

function TMyStream.Seek(dlibMove: Largeint; dwOrigin: Longint;
                        out libNewPosition: Largeint): HResult;
begin
  writedebug('Stream.Seek');
  Result := S_OK;
  try
    libNewPosition := FTheStream.Seek(Trunc(Int(dlibMove)), dwOrigin);
  except
    Result := STG_E_INVALIDFUNCTION;
  end;
end;

function TMyStream.SetSize(libNewSize: Largeint): HResult;
begin
  writedebug('Stream.SetSize');
  Result := S_OK;
  try
    FTheStream.SetSize(Trunc(Int(libNewSize)));
    GetSystemTimeAsFileTime(Fctime);
  except
    Result := STG_E_MEDIUMFULL;
  end;
end;

function TMyStream.CopyTo(stm: IStream; cb: Largeint; out cbRead: Largeint;
                          out cbWritten: Largeint): HResult;
var Buffer     : PChar;
    cb_Written : LargeInt;
begin
  writedebug('Stream.CopyTo');
  GetMem(Buffer, Trunc(Int(cb)));
  Result := S_OK;
  try
  try
    cbRead := FTheStream.Read(Buffer^, Trunc(Int(cb)));
    stm.Write(Buffer, Trunc(Int(cb)), @cb_Written);
    cbWritten := cb_Written;
    GetSystemTimeAsFileTime(Fatime);
  except
    Result := STG_E_MEDIUMFULL;
  end;
  finally
    FreeMem(Buffer, Trunc(Int(cb)));
  end;
end;

function TMyStream.Commit(grfCommitFlags: Longint): HResult;
begin
  writedebug('Stream.Commit');
  Result := S_OK;
end;

function TMyStream.Revert: HResult;
begin
  writedebug('Stream.Revert');
  Result := S_OK;
end;

function TMyStream.LockRegion(libOffset: Largeint; cb: Largeint;
                              dwLockType: Longint): HResult;
begin
  writedebug('Stream.LockRegion');
  Result := STG_E_INVALIDFUNCTION;
end;

function TMyStream.UnlockRegion(libOffset: Largeint; cb: Largeint;
                                dwLockType: Longint): HResult;
begin
  writedebug('Stream.UnlockRegion');
  Result := STG_E_INVALIDFUNCTION;
end;

function TMyStream.Stat(out statstg: TStatStg; grfStatFlag: Longint): HResult;
begin
  writedebug('Stream.Stat');
  with FStatStg do
   begin
     if grfStatFlag = STATFLAG_DEFAULT
      then lstrcpyW(pwcsName, 'Test');
     dwType := STGTY_LOCKBYTES;
     cbSize := FTheStream.Size;
     mtime := Fmtime;
     ctime := Fctime;
     atime := Fatime;
     grfMode := 0;
     grfLocksSupported := 0;
     clsid := CLSID_NULL;
     grfStateBits := 0;
   end;
  statstg := FStatStg;
  Result := S_OK;
end;

function TMyStream.Clone(out stm: IStream): HResult;
begin
  writedebug('Stream.Clone');
  Result := STG_E_INVALIDPOINTER;
end;

////////////////////////////////////////////////////////////////////////////////

initialization
begin
  if IsDebug then
   begin
     AssignFile(F, DebugFile);
     Rewrite(F);
     CloseFile(F);
   end;
  TComObjectFactory.Create(ComServer, TMyCustomMoniker, CLSID_MyCustomMoniker, 'MyMoniker', 'Test', ciMultiInstance);
end;

end.

// project source

library MyMoniker;

uses
  ComServ,
  _MyMoniker in '_MyMoniker.pas';

exports
  DllGetClassObject,
  DllCanUnloadNow,
  DllRegisterServer,
  DllUnregisterServer;

{$R *.RES}

begin
end.

// EOC //

OK, here the registry keys. Save them in a .reg file and double-click to merge them. I assumed the project's DLL resists in D:\Program Files, change the value accordingly.
The name of the moniker, slashmoniker in this case, can be changed by changing all
HKEY_CLASSES_ROOT\SlashMoniker
and
HKEY_CLASSES_ROOT\SlashMoniker.1
keys and the default values of
HKEY_CLASSES_ROOT\CLSID\{556F12A1-DE94-11D1-B4EA-0000E82D8A65}\ProgID
HKEY_CLASSES_ROOT\CLSID\{556F12A1-DE94-11D1-B4EA-0000E82D8A65}\VersionIndependentProgID
and
HKEY_CLASSES_ROOT\SlashMoniker\CurVer
It's not that difficult.

// BOC //
REGEDIT4

[HKEY_CLASSES_ROOT\SlashMoniker]
@="Slash's IE Moniker"

[HKEY_CLASSES_ROOT\SlashMoniker\CLSID]
@="{556F12A1-DE94-11D1-B4EA-0000E82D8A65}"

[HKEY_CLASSES_ROOT\SlashMoniker\CurVer]
@="SlashMoniker.1"

[HKEY_CLASSES_ROOT\SlashMoniker.1]
@="Slash's IE Moniker V1"

[HKEY_CLASSES_ROOT\SlashMoniker.1\CLSID]
@="{556F12A1-DE94-11D1-B4EA-0000E82D8A65}"

[HKEY_CLASSES_ROOT\CLSID\{556F12A1-DE94-11D1-B4EA-0000E82D8A65}]
@="Slash's IE Moniker V1"

[HKEY_CLASSES_ROOT\CLSID\{556F12A1-DE94-11D1-B4EA-0000E82D8A65}\InprocServer32]
"ThreadingModel"="Apartment"
@="D:\\Program Files\\MyMoniker.dll"

[HKEY_CLASSES_ROOT\CLSID\{556F12A1-DE94-11D1-B4EA-0000E82D8A65}\ProgID]
@="SlashMoniker.1"

[HKEY_CLASSES_ROOT\CLSID\{556F12A1-DE94-11D1-B4EA-0000E82D8A65}\Version]
@="1"

[HKEY_CLASSES_ROOT\CLSID\{556F12A1-DE94-11D1-B4EA-0000E82D8A65}\VersionIndependentProgID]
@="SlashMoniker"
// EOC //

If you have any questions, just ask.
Slash/d003303
0
 
ronit051397Commented:
0
 
freterAuthor Commented:
Hm...
I have seen that before, but it doesn't help me.
I need a DLL that can be invoke by Intenet Explorer, just like the ivtmon.dll that is referenced by the string "ivt" in the URL depicted in my question.
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
ronit051397Commented:
Sorry, I can't help you with this issue.
0
 
d003303Commented:
Yep, did that one some time ago. It was a pain in the ass to get all the information, because it is only well documented how to *use* monikers, but not how to *write* them.
I built a sample moniker that simply displays HTML files from a file system or an error message if the file was not found. E.g. you set the moniker root to
c:\hello
and type in IE
mk:@slashmoniker:/my/baby.html
it would load c:\hello\my\baby.html
Sure you could dispatch any path to anywhere.
You'll get the moniker code for 300 points, it took me about 5 weeks to figure all the details out.

Slash/d003303
0
 
freterAuthor Commented:
Slash/d003303:
One question before I increase the points for you:
Is your moniker able to provide the embedded images of the html page out to explorer?

Freter

0
 
d003303Commented:
Yo,
all embedded objects (images, plug-in codbases, etc.) that have a relative path are combined to a full qualified path by IE before they are requested. E.g. if <IMG SRC="/images/help.gif"> is part of a page provided by my moniker, IE would create the full referenced path mk:@slashmoniker:/images/help.gif.
Because IE builds full referenced URLs compilant to RFC 2068, you can also prefix the moniker root like M$ does. The "mk:@slashmoniker:" identifies the protocol (equi to http:), then comes the "//(server)" part, then a directory/file path (you may omit the server part). So if the page location of the above example would be mk:@slashmoniker://MyDatabase/about.html, IE would refer the picture path to mk:@slashmoniker://MyDatabase/images/help.gif.
This gives you flexibility on interpretation of the URL and organization of your database archive. E.g. you could also provide mk:@slashmoniker:MyServer//MyDatabase/about.html as a page location, the image would be in mk:@slashmoniker:MyServer//MyDatabase/images/help.gif. Or mk:@slashmoniker:MyDomain:MyServer//MyDatabase/about.html, etc.
You can do anything you like and easily run a website fromout a database.
Hope this answers your question.

Slash/d003303
0
 
freterAuthor Commented:
Slash:
Ok. I'll increase the points.

Freter
0
 
d003303Commented:
An example to register a moniker called by mk:@HelloWorld

// BOC //
REGEDIT4

[HKEY_CLASSES_ROOT\HelloWorld]
@="Hello World Moniker"

[HKEY_CLASSES_ROOT\HelloWorld\CLSID]
@="{556F12A1-DE94-11D1-B4EA-0000E82D8A65}"

[HKEY_CLASSES_ROOT\HelloWorld\CurVer]
@="HelloWorld.1"

[HKEY_CLASSES_ROOT\HelloWorld.1]
@="Hello World Moniker V1"

[HKEY_CLASSES_ROOT\HelloWorld.1\CLSID]
@="{556F12A1-DE94-11D1-B4EA-0000E82D8A65}"

[HKEY_CLASSES_ROOT\CLSID\{556F12A1-DE94-11D1-B4EA-0000E82D8A65}]
@="Hello World Moniker V1"

[HKEY_CLASSES_ROOT\CLSID\{556F12A1-DE94-11D1-B4EA-0000E82D8A65}\InprocServer32]
"ThreadingModel"="Apartment"
@="D:\\Program Files\\MyMoniker.dll"

[HKEY_CLASSES_ROOT\CLSID\{556F12A1-DE94-11D1-B4EA-0000E82D8A65}\ProgID]
@="HelloWorld.1"

[HKEY_CLASSES_ROOT\CLSID\{556F12A1-DE94-11D1-B4EA-0000E82D8A65}\Version]
@="1"

[HKEY_CLASSES_ROOT\CLSID\{556F12A1-DE94-11D1-B4EA-0000E82D8A65}\VersionIndependentProgID]
@="HelloWorld"

// EOC //

Slash/d003303
0
 
freterAuthor Commented:
Thanks a lot, Slash!
This is exactly what I have been looking for. It works perfectly for me.
I had only little time this morning to look through all of the code, so maybe I will have some questions regarding the source the next few days.

0
 
d003303Commented:
Ok, no prob.
0
 
freterAuthor Commented:
Hi Slash, still listening on this thread?

I've got some probs with the Moniker. When I use it with IE 4.0, everything is just fine, but when running in IE 3 (no matter which build #), it just reports an access violation in mshtml.dll after loading the 4th unique file.
I woul be *very* glad if you could spend a minute or two helping me with this bug!

Freter
0
 
d003303Commented:
Yo,
still listening. I just tried over and over, no problems.
So, do you still run the moniker in file-access mode or have you already bound it into the OLE structured storage ? If you are still working in a file system, could you send me an archive with these files ?
Also, take a look at the debug file and see where the moniker crashes. This is a very helpful information.

Slash/d003303
0
 
freterAuthor Commented:
Hm.
I used the code you provided here. Then I put five different really plain HTML files in the root and called them via the moniker. The important thing is: the fifth unique file will cause a crash. If you try to load files that are not unique (like call only two files alternatingly), no crash will occur.
This problem arises as well with the code that reads from a file system as well as with my code that binds to OLE Structured Storage. And: it only occurs with IE3x, *not* with IE4x!
I don't have the code here today, but I can send it to you tomorrow, together with the debug.txt.

Later
Freter
0
 
d003303Commented:
Ok, awaiting your mail :)
0
 
cdcoppolaCommented:
d003303,

Do you have a similar example that takes advantage of the IBindStatusCallback interface?


0
 
d003303Commented:
cdcoppola,

sorry, haven't done that yet.

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.