text: #include <private.h>
  
  WCHAR **SymbolNames;
  
  typedef BOOL ( __cdecl *PPDBOPEN2W )(
      const wchar_t *,
      LNGNM_CONST char *,
      EC *,
      wchar_t *,
      size_t,
      PDB **
      );
  
  typedef BOOL ( __cdecl *PPDBCLOSE ) (
      PDB* ppdb
      );
  
  typedef BOOL (__cdecl *PPDBCOPYTOW2) (
      PDB *ppdb,
      const wchar_t *szTargetPdb,
      DWORD dwCopyFilter,
      PfnPDBCopyQueryCallback pfnCallBack,
      void * pvClientContext
      );
  
  PPDBOPEN2W pPDBOpen2W;
  PPDBCLOSE  pPDBClose;
  PPDBCOPYTOW2 pPDBCopyToW2;
  wchar_t NewPdbName[_MAX_FNAME];
  
  CHAR SymbolName[2048];
  WCHAR SymbolNameW[2048];
  PWCHAR *SymbolsToRemove;
  ULONG SymbolCount;
  
  int
  __cdecl
  MyWcsCmp(const void*Ptr1, const void *Ptr2)
  {
      wchar_t*String1 = *(wchar_t**)Ptr1;
      wchar_t*String2 = *(wchar_t**)Ptr2;
  
  //    printf("String1: %p - %ws\nString2: %p - %ws\n%d\n", String1, String1, String2, String2, wcscmp(String1, String2));
      return (wcscmp(String1, String2));
  }
  
  __cdecl
  MyWcsCmp2(const void*Ptr1, const void *Ptr2)
  {
      wchar_t*String1 = (wchar_t*)Ptr1;
      wchar_t*String2 = *(wchar_t**)Ptr2;
  
  //    printf("String1: %p - %ws\nString2: %p - %ws\n%d\n", String1, String1, String2, String2, wcscmp(String1, String2));
      return (wcscmp(String1, String2));
  }
  
  
  BOOL
  LoadNamesFromSymbolFile(
      WCHAR *SymbolFileName
      )
  {
      FILE *SymbolFile;
      ULONG i;
  
      SymbolFile = _wfopen(SymbolFileName, L"rt");
      if (!SymbolFile)
          return FALSE;
  
      SymbolCount = 0;
      while (fgets(SymbolName,sizeof(SymbolName),SymbolFile)) {
          SymbolCount++;
      }
  
      if (fseek(SymbolFile, 0, SEEK_SET)) {
          fclose(SymbolFile);
          return FALSE;
      }
  
      SymbolsToRemove = (PWCHAR *) malloc(SymbolCount * sizeof(PWCHAR));
  
      if (!SymbolsToRemove) {
          fclose(SymbolFile);
          return FALSE;
      }
  
      SymbolCount = 0;
  
      while (fgets(SymbolName,sizeof(SymbolName),SymbolFile)) {
          // Remove trailing spaces
          if (strlen(SymbolName)) {
              PCHAR SymPtr = SymbolName + strlen(SymbolName) - 1;
              while ((*SymPtr == ' ') || (*SymPtr == '\r') || (*SymPtr == '\n')) {
                  *SymPtr = '\0';
                  SymPtr--;
              }
          }
  
          if (MultiByteToWideChar(CP_ACP,
                                  MB_PRECOMPOSED,
                                  SymbolName,
                                  -1,
                                  SymbolNameW,
                                  sizeof(SymbolNameW)/sizeof(SymbolNameW[0])) == 0) {
              fclose(SymbolFile);
              return FALSE;
          }
  
          SymbolsToRemove[SymbolCount] = malloc((wcslen(SymbolNameW) + 1) * sizeof(WCHAR));
          if (!SymbolsToRemove[SymbolCount]) {
              fclose(SymbolFile);
              return FALSE;
          }
  
          wcscpy(SymbolsToRemove[SymbolCount], SymbolNameW);
          SymbolCount++;
      }
  
      fclose(SymbolFile);
  
      qsort(&SymbolsToRemove[0], SymbolCount, sizeof(PWCHAR), MyWcsCmp);
  
      return TRUE;
  }
  
  
  BOOL PDBCALL PdbCopyFilterPublics (
      void *          pvClientContext,
      DWORD           dwFilterFlags,
      unsigned int    offPublic,
      unsigned int    sectPublic,
      unsigned int    grfPublic,
      const wchar_t * szPublic,
      wchar_t **      pszNewPublic
      ) {
  
      static size_t   cPubs = 0;
      static wchar_t  wszNewName[2048];
  
      if (SymbolCount > 1) {
          if (bsearch(szPublic, &SymbolsToRemove[0], SymbolCount, sizeof(PWCHAR), MyWcsCmp2)) {
              return FALSE;
          }
      } else {
          if (!wcscmp(szPublic, *SymbolsToRemove)) {
              return FALSE;
          }
      }
  
      return TRUE;
  
  //    if ((cPubs++ % 16) == 0) {
  //        if ((cPubs % 32) == 1) {
  //            wcscpy(wszNewName, szPublic);
  //            wcscat(wszNewName, L"_BobsYerUncle");
  //            *pszNewPublic = wszNewName;
  //        }
  //        return TRUE;
  //    }
  //    else {
  //        return FALSE;
  //    }
  }
  
  PDBCOPYCALLBACK PDBCALL PdbCopyQueryCallback(void * pv, PCC pccQuery) {
      switch (pccQuery) {
      case pccFilterPublics:
          return (PDBCOPYCALLBACK) PdbCopyFilterPublics;
          break;
      default:
          return NULL;
      }
  }
  
  void Usage(void)
  {
      _putws(L"Usage: removesym -d:<pdbdll path> -p:<pdbname> {-s:<symbol to remove> | -f:<file with symbols to remove>}");
  }
  
  const WCHAR szMsPdb60[] = L"\\mspdb60.dll";
  const WCHAR szMsPdb70[] = L"\\mspdb70.dll";
  
  int __cdecl wmain(int argc, wchar_t *argv[])
  {
      WCHAR *szPdbName = NULL;
      WCHAR *szNewPdbName = NULL;
      WCHAR *pSymbolName = NULL;
      WCHAR *pSymbolFileName = NULL;
      HINSTANCE hmodMsPdb;
      BOOL rc;
      LONG ErrorCode;
      WCHAR ErrorString[1024];
      PDB * pSrcPdb;
      int i;
      WCHAR PdbDllName[_MAX_PATH] = {0};
      WCHAR *pPdbDllPath = NULL;
      WCHAR const *pPdbDllName = szMsPdb60;
  
      // Grab the arguments
  
      if (argc < 4) {
          Usage();
          return 1;
      }
  
      i = 1;
  
      while (i < argc)
      {
          if (argv[i][0] == L'-' || argv[i][0] == L'/') {
              if (argv[i][1] == L'p' && argv[i][2] == ':') {
                  // Pdb Name
                  szPdbName = &argv[i][3];
              } else
              if (argv[i][1] == L's' && argv[i][2] == ':') {
                  // Single Symbol name
                  pSymbolName = &argv[i][3];
              } else
              if (argv[i][1] == L'f' && argv[i][2] == ':') {
                  // File with symbol names
                  pSymbolFileName = &argv[i][3];
              } else
              if (argv[i][1] == L'd' && argv[i][2] == ':') {
                  // Single Symbol name
                  pPdbDllPath = &argv[i][3];
              } else {
                  Usage();
                  return 1;
              }
          }
          i++;
      }
  
      if (!szPdbName) {
          _putws(L"Pdb name missing");
          Usage();
          return 1;
      }
  
      if (!pSymbolName && !pSymbolFileName) {
          _putws(L"Symbol name or file missing");
          Usage();
          return 1;
      }
  
      if (pSymbolName && pSymbolFileName) {
          _putws(L"Symbol name and symbol file specified - only one allowed");
          Usage();
          return 1;
      }
  
      if (!pPdbDllPath) {
          _putws(L"Pdb DllPath not specified");
          Usage();
          return 1;
      }
  
      // If there's a symfile, load it
  
      if (pSymbolFileName) {
          rc = LoadNamesFromSymbolFile(pSymbolFileName);
          if (!rc) {
              _putws(L"Unable do load names from symbol file");
              exit(1);
          }
      } else {
          SymbolsToRemove = &pSymbolName;
          SymbolCount = 1;
      }
  
  Retry:
      rc = FALSE;
      // Load mspdb60.dll and the necessar api's
  
      wcscpy(PdbDllName, pPdbDllPath);
      wcscat(PdbDllName, pPdbDllName);
  
      hmodMsPdb = LoadLibraryW(PdbDllName);
  
      if (!hmodMsPdb) {
          wprintf(L"Unable to loadlib %s\n", PdbDllName);
          goto Exit;
      }
  
      pPDBOpen2W = (PPDBOPEN2W) GetProcAddress(hmodMsPdb, "PDBOpen2W");
      if (!pPDBOpen2W) {
          wprintf(L"Unable to find PDBOpen2W in %s\n", PdbDllName);
          goto Exit;
      }
      pPDBClose = (PPDBCLOSE) GetProcAddress(hmodMsPdb, "PDBClose");
      if (!pPDBClose) {
          wprintf(L"Unable to find PDBClose in %s\n", PdbDllName);
          goto Exit;
      }
      pPDBCopyToW2 = (PPDBCOPYTOW2) GetProcAddress(hmodMsPdb, "PDBCopyToW2");
      if (!pPDBCopyToW2) {
          wprintf(L"Unable to find PDBCopyToW2 in %s\n", PdbDllName);
          goto Exit;
      }
  
      __try {
          rc = pPDBOpen2W(szPdbName, "r", &ErrorCode, ErrorString, sizeof(ErrorString) / sizeof(ErrorString[0]), &pSrcPdb);
          if (!rc) {
              wprintf(L"Unable to open pdb for changes with %s\n", PdbDllName);
              __leave;
          }
  
          szNewPdbName = _wtmpnam(NewPdbName);
  
          rc = pPDBCopyToW2(pSrcPdb, szNewPdbName, 1, PdbCopyQueryCallback, NULL);
  
          pPDBClose(pSrcPdb);
  
          if (!rc) {
              _putws(L"CopyTo operation failed");
              __leave;
          }
  
          rc = CopyFile(szNewPdbName, szPdbName, FALSE);
          if (!rc) {
              _putws(L"Unable to overwrite old pdb with new pdb");
          }
  
          DeleteFile(szNewPdbName);
  
      } __except (EXCEPTION_EXECUTE_HANDLER) {
            _putws(L"Exception occured in pdb api's");
            rc = FALSE;
      }
  
  Exit:
      if (hmodMsPdb) {
          FreeLibrary(hmodMsPdb);
          hmodMsPdb = NULL;
      }
  
      if (!rc) {
          if (pPdbDllName == szMsPdb60) {
              pPdbDllName = szMsPdb70;
              goto Retry;
          }
      }
      return(rc);
  }
  