home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / OCT_REG.PAK / REGISTER.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  10.6 KB  |  327 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectComponents
  3. // Copyright (c) 1994, 1996 by Borland International, All Rights Reserved
  4. //
  5. // Tool to load, register, unregister, and debug OLE2 inproc servers and EXEs.
  6. // Reads its command line to determine action, suggestion: use progman icons.
  7. // Does no registration itself, simply invokes functions in the OC component.
  8. // Brings up help dialog on empty command line; refer to that for usage info.
  9. //----------------------------------------------------------------------------
  10. #include <ocf/ocreg.h>
  11. #include <classlib/cmdline.h>
  12. #include <string.h>
  13. #include "register.rh"
  14. #include <shellapi.h>
  15.  
  16. #define DLLENTRY   "DllRegisterCommand"
  17. #define MSDLLREGSERVERENTRY "DllRegisterServer"
  18. #define MSDLLUNREGSERVERENTRY "DllUnregisterServer"
  19. #define REGISTER32 "REGIST32.EXE"
  20.  
  21. //
  22. // Error handling facility using local exception object
  23. //
  24. struct TLocalError {   // local exception object for this program
  25.   TLocalError(const char* title, const char* message)
  26.                   : Title(title),    Message(message) {}
  27.   const char* Title;
  28.   const char* Message;
  29. };
  30.  
  31. static void Error(const char* title, const char* message)
  32. {
  33.   throw TLocalError(title, message);
  34. }
  35.  
  36. static inline void ErrorIf(int error, const char* title, int resId)
  37. {
  38.   if (error)
  39.     Error(title, (char*)resId);
  40. }
  41. static inline void ErrorIf(int error, int resId, const char* message)
  42. {
  43.   if (error)
  44.     Error((char*)resId, message);
  45. }
  46.  
  47. static inline void ErrorIf(int error, const char* title, const char* message)
  48. {
  49.   if (error)
  50.     Error(title,message);
  51. }
  52.  
  53.  
  54. //
  55. // File type determination
  56. //
  57.  
  58. const int ftExists  = 1;
  59. const int ftModule  = 2;
  60. const int ftLibrary = 4;
  61. const int ft32Bit   = 8;
  62.  
  63. int GetFileType(const char far* fileName)
  64. {
  65.   HFILE hdl = _lopen(fileName, OF_READ);
  66.   if (hdl == HFILE_ERROR)
  67.     return 0;
  68.   int type = ftExists;
  69.   char buf[64];
  70.   if (_lread(hdl, buf, sizeof(buf)) == sizeof(buf) &&
  71.       *(short*)(buf+0x00) == 0x5A4D &&  // check if executable image
  72.       *(short*)(buf+0x18) == 0x0040) {  // check if NEWEXE type, not just DOS
  73.     long offset = *(long*)(buf+0x3C);
  74.     if (_llseek(hdl, offset, 0) != HFILE_ERROR &&
  75.         _lread(hdl, buf, sizeof(buf)) == sizeof(buf)) {
  76.       if (*(short*)(buf+0x00) == 0x454E) {        // check if 16-bit module
  77.         type |= ftModule;
  78.         if (*(short*)(buf+0x0C) & 0x8000)
  79.           type |= ftLibrary;
  80.       }
  81.       else if (*(short*)(buf+0x00) == 0x4550) { // check if 32-bit module
  82.         type |= (ftModule | ft32Bit);
  83.         if (*(short*)(buf+0x16) & 0x2000)
  84.           type |= ftLibrary;
  85.       }
  86.     }
  87.   }
  88.   _lclose(hdl);
  89.   return type;
  90. }
  91.  
  92. //
  93. // DLL loading and entry point management class
  94. //
  95. struct TDllData {
  96.   TDllData() : Lib(0)   {::OleInitialize(0);}
  97.  ~TDllData() {FreeLib(); ::OleUninitialize();}
  98.  
  99.   bool LoadLib(const char* name);
  100.   void FreeLib() {if (Lib) ::FreeLibrary(Lib); Lib = 0;}
  101.   bool GetEntry();
  102.   HRESULT CallEntry(const char far* cmdLine);
  103.  
  104.   HINSTANCE Lib;
  105.   union {
  106.     TDllRegisterCommand  DllRegisterCommand;
  107.     HRESULT STDAPICALLTYPE (*MsDllRegServer)();
  108.     HRESULT STDAPICALLTYPE (*MsDllUnRegServer)();
  109.     FARPROC  DllRegProc;
  110.   };
  111.   bool DllRegisterCommandEntry;
  112. };
  113.  
  114. bool TDllData::LoadLib(const char* name)
  115. {
  116.   DllRegProc = 0;
  117.   FreeLib();
  118.   if ((Lib=::LoadLibrary(name)) >= (HINSTANCE)HINSTANCE_ERROR)
  119.     return true;
  120.   Lib = 0;
  121.   return false;
  122. }
  123.  
  124. bool TDllData::GetEntry()
  125. {
  126.   if ((DllRegProc = ::GetProcAddress(Lib, DLLENTRY)) != 0) {
  127.     DllRegisterCommandEntry = true;
  128.     return true;
  129.   }
  130.   DllRegisterCommandEntry = false;  // Will have to call Dll[R|Unr]egisterServer
  131.   // note:  we're getting the entry for DllRegisterServer but it may change
  132.   // (in CallEntry) to the entry for DllUnregisterServer.
  133.   return (DllRegProc = ::GetProcAddress(Lib, MSDLLREGSERVERENTRY)) != 0;
  134. }
  135.  
  136. HRESULT TDllData::CallEntry(const char far* cmdLine)
  137. {
  138.   // It's one of ours
  139.   if (DllRegisterCommandEntry)
  140.     return (*DllRegisterCommand)(cmdLine);
  141.  
  142.   // We need to work with a lowercase command line
  143.   TAPointer<char> lwcLine = new char[strlen(cmdLine)+1];
  144.   strcpy(lwcLine, cmdLine);
  145.   strlwr(lwcLine);
  146.  
  147.   // DllUnregisterServer
  148.   if (strstr(lwcLine, "unregserver")) {
  149.     if ((DllRegProc = ::GetProcAddress(Lib, MSDLLUNREGSERVERENTRY)) == 0)
  150.       return ResultFromScode(E_UNEXPECTED);
  151.     else
  152.       return (*MsDllUnRegServer)();
  153.   }
  154.  
  155.   // DllRegisterServer
  156.   if (strstr(lwcLine, "regserver"))
  157.     return (*MsDllRegServer)();
  158.  
  159.   // Neither RegServer nor UnRegServer Selected, just return
  160.   return ResultFromScode(S_OK);
  161. }
  162.  
  163. //
  164. // Command option state flags
  165. //
  166. const int rfDone     = 1; // force break from loop
  167. const int rfNoValue  = 2; // no value allowed for option
  168. const int rfReqValue = 4; // value required for option
  169. const int rfOptValue = 8; // optional value for option
  170. const int rfDebug   = 16; // special test for debug option
  171. const int rfTypeLib = 32; // check for typelib generation errors
  172. const int rfRegServer=64; // check for registration errors
  173. const int rfQuietReg=128; // suppress registry error reporting
  174.  
  175. //
  176. // Command option table
  177. //
  178. struct {
  179.   char*   String;
  180.   int     Flags;
  181. } table[] = {
  182.   {"Language",   rfOptValue },
  183.   {"RegServer",  rfOptValue | rfRegServer },
  184.   {"UnregServer",rfNoValue },
  185.   {"TypeLib",    rfOptValue | rfTypeLib },
  186.   {"Debug",      rfNoValue | rfDebug },
  187.   {"QuietReg",   rfQuietReg | rfNoValue },
  188. };
  189. const int tableCount = sizeof(table)/sizeof(table[0]);
  190.  
  191. #define MAX_CMD_LINE 256
  192.  
  193. bool CALLBACK __export
  194. HelpProc(HWND hDlg, UINT msg, WPARAM /*wParam*/, LPARAM /*lParam*/)
  195. {
  196.   if (msg != WM_COMMAND)
  197.     return msg == WM_INITDIALOG;
  198.   ::EndDialog(hDlg, TRUE);
  199.   return true;
  200. }
  201.  
  202. int PASCAL
  203. WinMain(HINSTANCE hInst, HINSTANCE/*hPrev*/, char far* cmdLine, int/*show*/)
  204. {
  205.   TCmdLine cmd(cmdLine);
  206.   TDllData dll;
  207.   int optFlags;
  208.   int curFlags;
  209.   char cmdbuf[MAX_CMD_LINE + sizeof(REGISTER32)];  // complete command line
  210.   char modName[MAX_CMD_LINE]; // copy of module name only, including file path
  211.   char* execmd;               // command line for EXE, include module path
  212.   char* regcmd;               // command line for DLL, no file path
  213.   char* cmdptr;
  214.   int tblIndex;
  215.   char regBuf[80];            // holds error string from registry
  216.  
  217.   try {
  218.     if (cmd.NextToken() != TCmdLine::Name)
  219.       return ::DialogBox(hInst, MAKEINTRESOURCE(IDD_HELP), 0,(DLGPROC)HelpProc);
  220.     do {   // module loop
  221.       optFlags = 0;
  222.       curFlags = rfNoValue;
  223.       strcpy(cmdbuf, REGISTER32);  // set up to spawn 32-bit tool from 16-bit
  224.       execmd = cmdbuf + strlen(cmdbuf);
  225.       *execmd++ = ' ';             // start of command line for EXE
  226.       memcpy(execmd, cmd.Token, cmd.TokenLen);
  227.       cmdptr = execmd + cmd.TokenLen;
  228.       *cmdptr = 0;   // temp. terminate for strchr and strcpy
  229.       if ((regcmd = strchr(execmd, '+')) != 0)  // test for "tdw+module.exe"
  230.         *regcmd++ = ' ';
  231.       else
  232.         regcmd = execmd;
  233.       strcpy(modName, regcmd);
  234.       *cmdptr++ = ' ';
  235.       regcmd = cmdptr;             // reg options only, for DLL, no pathname
  236.       strcpy(cmdptr, "/QuietReg ");
  237.       cmdptr += strlen(cmdptr);
  238.       do {
  239.         switch (cmd.NextToken()) {
  240.           case TCmdLine::Name:
  241.           case TCmdLine::Done:
  242.             ErrorIf(!optFlags, modName, IDS_NOOPTIONS);
  243.             curFlags |= rfDone;  // break out of loop
  244.             continue;
  245.           case TCmdLine::Option:
  246.             tblIndex = 0;
  247.             while (strnicmp(cmd.Token, table[tblIndex].String, cmd.TokenLen))
  248.               ErrorIf(++tblIndex == tableCount, IDS_UNKNOWNOPT, cmd.Token);
  249.             curFlags = table[tblIndex].Flags;
  250.             optFlags |= curFlags;
  251.             if (curFlags & rfQuietReg)
  252.               break;
  253.             *cmdptr++ = '/'; // use slash for option, dash needs leading space
  254.             strcpy(cmdptr, table[tblIndex].String);
  255.             cmdptr += strlen(table[tblIndex].String);
  256.             break;
  257.           case TCmdLine::Value:
  258.             ErrorIf((curFlags & rfNoValue), cmd.Token, IDS_MISSINGOPT);
  259.             curFlags = rfNoValue;   // prevent another value without option
  260.             *cmdptr++ = '=';
  261.             memcpy(cmdptr, cmd.Token, cmd.TokenLen);
  262.             cmdptr += cmd.TokenLen;
  263.             break;
  264.         }
  265.       } while (!(curFlags & rfDone));
  266.       *cmdptr = 0;
  267.  
  268.       int fileType = GetFileType(modName);
  269.       ErrorIf(!(fileType & ftExists), IDS_NOFINDMOD,  modName);
  270.       ErrorIf(!(fileType & ftModule), IDS_INVALIDMOD, modName);
  271.       if (fileType & ftLibrary) {
  272. #ifdef __WIN32__
  273.         ErrorIf(!(fileType&ft32Bit),IDS_CANTLOAD16,modName);
  274.         {
  275. #else
  276.         if (fileType & ft32Bit) {
  277.           uint execStat = ::WinExec(cmdbuf, SW_SHOW);
  278.           ErrorIf(execStat < (uint)HINSTANCE_ERROR, IDS_CANTLOAD32, modName);
  279.         }
  280.         else {
  281. #endif
  282.           ErrorIf(!dll.LoadLib(modName), IDS_NOLOADMOD, modName);
  283.           ErrorIf(!dll.GetEntry(), IDS_NOENTRYPNT, DLLENTRY);
  284.           ErrorIf(dll.CallEntry(regcmd) != NOERROR, IDS_REGFAILURE, execmd);
  285.           if (optFlags & rfDebug)
  286.             ::MessageBox(0, "Press OK to unload when debugging is finished",
  287.                          "DLL loaded for debugging", MB_OK);
  288.         }
  289.       }
  290.       else {
  291.         uint execStat = ::WinExec(execmd, SW_HIDE);
  292.         ErrorIf(execStat < (uint)HINSTANCE_ERROR, IDS_NOLOADMOD, modName);
  293.       }
  294.       if (optFlags & rfQuietReg) // ignore errors if spawned from another app
  295.         continue;
  296.       long buflen = sizeof(regBuf);
  297.       if ((optFlags & rfRegServer) && S_OK ==
  298.           ::RegQueryValue(TRegKey::ClassesRoot,"OcErr_RegServer", regBuf,&buflen)){
  299.         ::RegDeleteKey(TRegKey::ClassesRoot, "OcErr_RegServer");
  300.         Error((char*)IDS_REGFAILURE, regBuf);
  301.       }
  302.       if ((optFlags & rfTypeLib) && S_OK ==
  303.           ::RegQueryValue(TRegKey::ClassesRoot, "OcErr_Typelib", regBuf,&buflen)){
  304.         ::RegDeleteKey(TRegKey::ClassesRoot, "OcErr_Typelib");
  305.         Error((char*)IDS_TYPELIBERR, regBuf);
  306.       }
  307.     } while (cmd.Kind != TCmdLine::Done);
  308.     return 0;
  309.   }
  310.  
  311.   catch (TLocalError& xcpt) {
  312.     char msgbuf[80];
  313.     const char ** pmsg;
  314.     if (*(pmsg = &xcpt.Message) <= (const char*)IDS_MAX ||
  315.         *(pmsg = &xcpt.Title)   <= (const char*)IDS_MAX)
  316.     {
  317.       ::LoadString(hInst, *(unsigned*)pmsg, msgbuf, sizeof(msgbuf));
  318.       *pmsg = msgbuf;
  319.     }
  320.     ::MessageBox(0, xcpt.Message, xcpt.Title, MB_OK);
  321.   }
  322.   catch (xmsg& xcpt) {    // should not occur, but check anyway while catching
  323.     ::MessageBox(0, xcpt.why().c_str(), "Exception", MB_OK);
  324.   }
  325.   return 1;
  326. }
  327.