home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / oct_reg.pak / REGISTER.CPP < prev    next >
C/C++ Source or Header  |  1997-07-23  |  10KB  |  285 lines

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