`
lobin
  • 浏览: 390759 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

C:运行库

 
阅读更多

C

 

C运行库(glibc, GNU C Library)

参考C运行库实现https://ftp.gnu.org/gnu/glibc/glibc-2.0.6.tar.gz

 

Windows下VC C运行库

msvcrt.dll

msvcrt20.dll

msvcrt40.dll

MSVCRTD.DLL

以上不同dll应用于不同的vc版本,MSVCRTD.DLL用于debug。

 

msvcr100.dll

msvcr100_clr0400.dll

msvcr100d.dll

msvcr110.dll

msvcr71.dll

以上不同dll应用于不同的vc版本,msvcr100d.dll用于debug。

 

静态链接库

LIBC.LIB

LIBCD.LIB

LIBCMT.LIB

LIBCMTD.LIB

 

C++运行库

LIBCP.LIB

LIBCPD.LIB

LIBCPMT.LIB

LIBCPMTD.LIB

LIBCPD.LIB用于debug。

LIBCPMT.LIB,LIBCPMTD.LIB为多线程实现,LIBCPMTD.LIB用于debug。

 

C/C++ entry

写道
mainCRTStartup(void)
wmainCRTStartup(void)
WinMainCRTStartup(void)
wWinMainCRTStartup(void)

Purpose:
These routines do the C runtime initialization, call the appropriate
user entry function, and handle termination cleanup. For a managed
app, they then return the exit code back to the calling routine, which
is the managed startup code. For an unmanaged app, they call exit and
never return.

Entry:
Function: User entry called:
mainCRTStartup main
wmainCRTStartup wmain
WinMainCRTStartup WinMain
wWinMainCRTStartup wWinMain

 

 

malloc

 

 

#define mALLOc          malloc

 

 

 

#if __STD_C
Void_t* mALLOc(size_t bytes)
#else
Void_t* mALLOc(bytes) size_t bytes;
#endif
{
  arena *ar_ptr;
  INTERNAL_SIZE_T nb; /* padded request size */
  mchunkptr victim;

#if defined(_LIBC) || defined(MALLOC_HOOKS)
  if (__malloc_hook != NULL) {
    Void_t* result;

    result = (*__malloc_hook)(bytes);
    return result;
  }
#endif

  nb = request2size(bytes);
  arena_get(ar_ptr, nb);
  if(!ar_ptr)
    return 0;
  victim = chunk_alloc(ar_ptr, nb);
  (void)mutex_unlock(&ar_ptr->mutex);
  if(!victim) {
    /* Maybe the failure is due to running out of mmapped areas. */
    if(ar_ptr != &main_arena) {
      (void)mutex_lock(&main_arena.mutex);
      victim = chunk_alloc(&main_arena, nb);
      (void)mutex_unlock(&main_arena.mutex);
    }
    if(!victim) return 0;
  }
  return chunk2mem(victim);
}
 
#define request2size(req) \
 (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \
  (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \
   (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
 
 
#define arena_get(ptr, size) do { \
  Void_t *vptr = NULL; \
  ptr = (arena *)tsd_getspecific(arena_key, vptr); \
  if(ptr && !mutex_trylock(&ptr->mutex)) { \
    THREAD_STAT(++(ptr->stat_lock_direct)); \
  } else \
    ptr = arena_get2(ptr, (size)); \
} while(0)

static arena *
#if __STD_C
arena_get2(arena *a_tsd, size_t size)
#else
arena_get2(a_tsd, size) arena *a_tsd; size_t size;
#endif
{
  arena *a;
  heap_info *h;
  char *ptr;
  int i;
  unsigned long misalign;

  if(!a_tsd)
    a = a_tsd = &main_arena;
  else {
    a = a_tsd->next;
    if(!a) {
      /* This can only happen while initializing the new arena. */
      (void)mutex_lock(&main_arena.mutex);
      THREAD_STAT(++(main_arena.stat_lock_wait));
      return &main_arena;
    }
  }

  /* Check the global, circularly linked list for available arenas. */
  do {
    if(!mutex_trylock(&a->mutex)) {
      THREAD_STAT(++(a->stat_lock_loop));
      tsd_setspecific(arena_key, (Void_t *)a);
      return a;
    }
    a = a->next;
  } while(a != a_tsd);

  /* Nothing immediately available, so generate a new arena. */
  h = new_heap(size + (sizeof(*h) + sizeof(*a) + MALLOC_ALIGNMENT));
  if(!h)
    return 0;
  a = h->ar_ptr = (arena *)(h+1);
  for(i=0; i<NAV; i++)
    init_bin(a, i);
  a->next = NULL;
  a->size = h->size;
  tsd_setspecific(arena_key, (Void_t *)a);
  mutex_init(&a->mutex);
  i = mutex_lock(&a->mutex); /* remember result */

  /* Set up the top chunk, with proper alignment. */
  ptr = (char *)(a + 1);
  misalign = (unsigned long)chunk2mem(ptr) & MALLOC_ALIGN_MASK;
  if (misalign > 0)
    ptr += MALLOC_ALIGNMENT - misalign;
  top(a) = (mchunkptr)ptr;
  set_head(top(a), (((char*)h + h->size) - ptr) | PREV_INUSE);

  /* Add the new arena to the list. */
  (void)mutex_lock(&list_lock);
  a->next = main_arena.next;
  main_arena.next = a;
  (void)mutex_unlock(&list_lock);

  if(i) /* locking failed; keep arena for further attempts later */
    return 0;

  THREAD_STAT(++(a->stat_lock_loop));
  return a;
}
 

 

 

内嵌汇编

VC下内嵌汇编的例子:(Intel汇编语法)

// cmpxchg op1, op2 
// 
// cmpxchg use al, ax, eax, rax as output. 
// if al, ax, eax, rax equals op1, op2 loaded into op1, else, load op2 into al, ax, eax, rax.

short cmpxchg_s(short v_exchange, short* v_ptr, short v_compare)
{
  __asm mov edx, v_ptr; // mov v_ptr to edx
  __asm mov ax, v_compare; // mov v_compare to ax
  __asm mov cx, v_exchange; // mov v_exchange to cx

  
  __asm cmpxchg word ptr [edx], cx;

  // below comment code use to get the output of cmpxchg and return. but 
  // it's is needless. by defult, the last statement's result returned. 
  // in this case, the output of cmpxchg is returned.

  //__asm mov v_exchange, ax;
  //return v_exchange;
}

int cmpxchg_sx(short v_exchange, short* v_ptr, short v_compare)
{
  return cmpxchg_s(v_exchange, v_ptr, v_compare) == v_compare;
}

int cmpxchg(int v_exchange, int* v_ptr, int v_compare)
{
  __asm mov edx, v_ptr; // mov v_ptr to edx
  __asm mov eax, v_compare; // mov v_compare to ax
  __asm mov ecx, v_exchange; // mov v_exchange to cx

  __asm cmpxchg dword ptr [edx], ecx;

  // below comment code use to get the output of cmpxchg and return. but 
  // it's is needless. by defult, the last statement's result returned. 
  // in this case, the output of cmpxchg is returned.

  //__asm mov v_exchange, eax;
  //return v_exchange;
}

int cmpxchg_x(int v_exchange, int* v_ptr, int v_compare)
{
  return cmpxchg(v_exchange, v_ptr, v_compare) == v_compare;
}

 

 

gnulib

参考另一篇文章:https://lobin.iteye.com/blog/609813

ANSI C grammar, Lex specification,http://www.lysator.liu.se/c/ANSI-C-grammar-l.html

https://port70.net/~nsz/c/c11

Programming languages -- C,https://port70.net/~nsz/c/c11/n1570.html

ANSI C Specification,http://eli-project.sourceforge.net/c_html/c.html

Rationale for American National Standard for Information Systems - Programming Language - C,http://www.lysator.liu.se/c/rat/title.html

 

 

 

select & poll

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <poll.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
 
#define PORT 6002
 
//最多处理的connect
#define BACKLOG 5
 
//当前的连接数
int currentClient = 0;
 
//数据接受 buf
#define REVLEN 10
char recvBuf[REVLEN];
 
#define OPEN_MAX 1024
 
 
struct pollfd* _fd_init(struct pollfd* const fd_set) 
{
struct pollfd *poll_fd_set;
if (fd_set == NULL)
{
poll_fd_set = (struct pollfd *) malloc(OPEN_MAX * sizeof(struct pollfd));
}
else 
{
poll_fd_set = fd_set;
}
return poll_fd_set;
}
 
void _fd_zero(struct pollfd* fd_set) 
{
    for(int i = 0; i < OPEN_MAX; i++)
    {
        fd_set[i].fd = -1;
    }
}
 
void _fd_set(int fd, struct pollfd* const fd_set) 
{
fd_set[0].fd = fd;
    fd_set[0].events = POLLIN; //POLLRDNORM;
}
 
 
class SocketException 
{
private:
 
int errorCode;
 
char *message;
 
public:
 
SocketException(int errorCode) 
{
this->errorCode = errorCode;
this->message = NULL;
}
 
SocketException(int errorCode, char *message) 
{
this->errorCode = errorCode;
this->message = message;
}
 
int getCode() 
{
return errorCode;
}
 
char* getMessage() 
{
return message;
}
};
 
class HardSocket 
{
private: 
 
int sfd;
 
public:
 
HardSocket() throw (SocketException)
{
/**
* On success, a file descriptor for the new socket is returned.  On 
* error, -1 is returned, and errno is set appropriately.
*/
int fd = socket(AF_INET, SOCK_STREAM, 0);
//fd = -1;
if (fd == -1)
{
int error = errno;
throw SocketException(error);
} 
this->sfd = fd;
}
 
~HardSocket() 
{
printf("~HardSocket\n");
}
 
int getPlainSocket() 
{
return this->sfd;
}
 
void bind(int port) throw (SocketException)
{
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family  =  AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 
int error = ::bind(this->sfd, (struct sockaddr*) &server_addr, sizeof(server_addr));
if(error == -1) 
{
error = errno;
throw SocketException(error);
}
}
 
void listen() throw (SocketException)
{
this->listen(50);
}
 
void listen(int backlog) throw (SocketException)
{
int error = ::listen(this->sfd, backlog);
if(error == -1) 
{
error = errno;
throw SocketException(error);
}
}
};
 
 
class Poll
{
 
};
 
 
int main()
{
HardSocket *socket = NULL;
try
{
socket = new HardSocket();
socket->bind(PORT);
socket->listen();
}
catch (SocketException e)
{
printf("socket error %d\n", e.getCode());
// 有问题, 这里实例化一个socket对象时抛出异常的话, 析构函数不会被调用以释放对象资源
//sleep(5000);
return 1;
}
 
/**
* struct pollfd {
     *     int   fd;         // file descriptor 
     *     short events;     // requested events 
     *     short revents;    // returned events 
     * };
*/
struct pollfd clientfd[OPEN_MAX];
_fd_zero(clientfd);
_fd_set(socket->getPlainSocket(), clientfd);
 
int nfds = 0;
while(1) 
{
        int timeout = 3000;
        int error = poll(clientfd, nfds+1, timeout);
 
        if(error < 0) // On error, -1 is returned, and errno is set appropriately.
        {
            printf("select error %d\n", errno);
            break;
        }
        else if(error == 0) // A value of 0 indicates that the call timed out and no file descriptors were ready.
        {
            printf("timeout ...\n");  
            continue;  
        }
 
        for(int i = 0; i <= nfds; i++)  
        {  
            if(clientfd[i].fd < 0) 
{
                continue;
}
 
if (clientfd[i].fd == socket->getPlainSocket())
{
/**
* Case indicates that one event that data to read (POLLIN or POLLRDNORM) contained.
* 
* // The following values are defined by XPG4. 
* #define POLLRDNORM POLLIN
*/
if (clientfd[i].revents & POLLIN) 
{
printf("clientfd[%d].revents & POLLIN %d(0x%x) clientfd[%d].revents %d(0x%x), POLLIN %d(0x%x)\n", 
i, 
clientfd[i].revents & POLLIN, 
clientfd[i].revents & POLLIN, 
i, 
clientfd[i].revents, 
clientfd[i].revents, 
POLLIN, 
POLLIN);
 
int sockSvr = accept(socket->getPlainSocket(), NULL, NULL);//(struct sockaddr*)&client_addr
if(sockSvr == -1)  
{
printf("accpet error\n");  
}
else  
{
currentClient++;  
}
 
for(i=0; i<OPEN_MAX; i++)  
{
if(clientfd[i].fd<0)  
{
clientfd[i].fd = sockSvr;  
break;  
}
}
if(i == OPEN_MAX) 
{
printf("too many connects\n");  
return -1;  
}
clientfd[i].events = POLLIN;//POLLRDNORM;  
if(i > nfds) 
{
nfds = i;
}
}
            }
else if (clientfd[i].revents & (POLLIN | POLLERR)) // POLLRDNORM  
            {
printf("clientfd[%d].revents & (POLLIN | POLLERR) %d(0x%x) clientfd[%d].revents %d(0x%x), POLLIN %d(0x%x), POLLERR %d(0x%x)\n", 
i, 
clientfd[i].revents & (POLLIN | POLLERR), 
clientfd[i].revents & (POLLIN | POLLERR), 
i, 
clientfd[i].revents, 
clientfd[i].revents, 
POLLIN, 
POLLIN, 
POLLERR, 
POLLERR);
int recvLen = 0;
                if(recvLen != REVLEN)  
                {
                    while(1)  
                    {
printf("recv....\n");
                        //recv数据
                        int bytes = recv(clientfd[i].fd, (char *) recvBuf+recvLen, REVLEN - recvLen, 0);
                        if(bytes == 0) 
                        {
printf("stream socket %d peer has performed an orderly shutdown\n", clientfd[i].fd);
                            clientfd[i].fd = -1;
                            recvLen = 0;
                            break;
                        }  
                        else if(bytes == -1) 
                        {
printf("receive a message from a socket error %d\n", errno);
                            clientfd[i].fd = -1;
                            recvLen = 0;
                            break;
                        }
                        //数据接受正常  
                        recvLen = recvLen + bytes;
                        if(recvLen < REVLEN) 
                        {
                            continue;
                        }
                        else
                        {
                            //数据接受完毕  
                            printf("buf = %s\n",  recvBuf);
                            //close(client[i].fd);
                            //client[i].fd = -1;
                            recvLen = 0;
                            break;
                        }
                    }
                }
            }
        }
    }
 
    return 0;
}

select

#pragma comment(lib,"ws2_32.lib") 
 
#include <stdio.h>
#include <string.h>
#include <WINSOCK2.H>
 
#include <log.h>
#include "socket/HardSocket.h"
#include "socket/LightSocket.h"
#include "SelectEvent.hpp"
 
#define INT_SERVER_PORT 6002
#define STR_SERVER_IP "127.0.0.1"
#define INT_DATABUFFER_SIZE 100
 
class SelectEventBusinessHandler : public SelectEvent 
{
 
public:
 
void onAccept(LightSocket &socket)
{
sockaddr_in addr = socket.getSocketAddress();
debug("handle on accept event from %s:%d(socket %d)", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), socket.getPlainSocket());
}
 
void onMessage(LightSocket &socket, char *bytes)
{
sockaddr_in addr = socket.getSocketAddress();
//打印接收的数据
        info("recv from %s:%d\ndata:%s", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), bytes);
}
};
 
 
class Select : public HardSocket 
{
 
private: 
 
 
fd_set fd;
 
SelectEvent* eventHandler;
 
public:
Select() 
{
Socket::init(AF_INET, SOCK_STREAM, 0);
eventHandler = new SelectEventBusinessHandler();
 
FD_ZERO(&fd);
FD_SET(this->getPlainSocket(), &fd);
}
 
void select()
{
fd_set fdOld = fd;
//timeval tm;
//tm.tv_sec = 0;
//tm.tv_usec = 1000;
        int selected = ::select(0, &fdOld, NULL, NULL, NULL);  
        
if (selected == SOCKET_ERROR)  
        {  
            //WSACleanup();   
//printf("Faild to select sockt in server!/r/n");  
            int error = WSAGetLastError();
warn("select error %d", error);
Sleep(100);  
        }
else if (selected == 0) 
{
warn("select error, time limit expired");
}
else 
        {
            for(int i = 0;i < fd.fd_count; i++) 
            {
SOCKET sfd = fd.fd_array[i];
                if (FD_ISSET(sfd, &fdOld)) 
                {
                    //如果socket是服务器,则接收连接
                    if (sfd == this->getPlainSocket()) 
{
onAccept();
                    }
                    else //非服务器,接收数据(因为fd是读数据集)
                    {
onRead(sfd);
                    }
                }
else 
{
warn("socket fd %d not in fd set", sfd);
}
            }
        }
}
 
void onAccept() 
{
sockaddr_in addrAccept;
        int so_sockaddr_in = sizeof(sockaddr_in);
memset(&addrAccept, 0, so_sockaddr_in);
 
 
        SOCKET sockAccept = ::accept(this->getPlainSocket(), (sockaddr *) &addrAccept, &so_sockaddr_in);  
        if (sockAccept == INVALID_SOCKET) 
        {
   warn("accepted an invalid socket connection");
return;
}
        FD_SET(sockAccept, &fd);
        //FD_SET(sockAccept,&fdOld);
        info("%s:%d has connected server!", inet_ntoa(addrAccept.sin_addr), ntohs(addrAccept.sin_port));
 
LightSocket *cs = new LightSocket(sockAccept);
cs->setSocketAddress(addrAccept);
eventHandler->onAccept(*cs);
}
 
void onRead(SOCKET sfd) 
{
char szDataBuff[INT_DATABUFFER_SIZE];///////
        memset(szDataBuff, 0, INT_DATABUFFER_SIZE);
szDataBuff[INT_DATABUFFER_SIZE - 1] = '\0';
 
        int bytes = recv(sfd, szDataBuff, INT_DATABUFFER_SIZE - 1, 0);
        
sockaddr_in addr;
int so_sockaddr_in = sizeof(sockaddr_in);
memset(&addr, 0, so_sockaddr_in);
        getpeername(sfd, (sockaddr *) &addr, &so_sockaddr_in);
        if (bytes == SOCKET_ERROR)  
        {
int error = WSAGetLastError();
            warn("Fail to receive data from %s:%d error %d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), error);
closesocket(sfd);
            FD_CLR(sfd, &fd);
            //i--;
            return;
        }
 
        if (bytes == 0) 
        {
            //客户socket关闭  
            warn("%s:%d has closed!", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
 
            closesocket(sfd);
            FD_CLR(sfd, &fd);
            //i--;
        }  
          
        if (bytes > 0) 
        {
LightSocket *cs = new LightSocket(sfd);
cs->setSocketAddress(addr);
eventHandler->onMessage(*cs, szDataBuff);
        }
}
};
 
void main(void)
{
///*
Select *socket = new Select();
 
bool bReuseAddr = true;
socket->setSocketOption(SOL_SOCKET, SO_REUSEADDR, (char *) &bReuseAddr, sizeof(bReuseAddr));
    //unsigned   long cmd = 1;
    //iResult= ioctlsocket(sockServer,FIONBIO,&cmd);
socket->bind(INT_SERVER_PORT);
socket->listen(5);
 
    info("Start server...");
while(1)
{
        socket->select();
    }  
    WSACleanup();
}

 

开发自己的C运行库及标准库

https://www.iteye.com/blog/lobin-620212

0
0
分享到:
评论

相关推荐

    C语言运行时库C语言运行时库

    C语言运行时库C语言运行时库C语言运行时库C语言运行时库C语言运行时库C语言运行时库C语言运行时库C语言运行时库C语言运行时库C语言运行时库C语言运行时库C语言运行时库C语言运行时库C语言运行时库C语言运行时库C语言...

    重装系统后必装:常用软件运行库(VB+VC运行库)2010.09

    这个“常用运行库”包的就是为了解决这类问题而生的,原版系统自带的运行库比较旧且数量少,而这个包则涵盖了目前各个版本的运行库和常用的控件,可以起到增强系统的作用。 这是装完系统后必装的东西,就像Flash...

    Visual C++运行库合集(vc2005,vc2008,vc2010,VC2012运行库)

    Microsoft Visual C++运行库合集由国外网友McRip制作,包含了VC2005、VC2008、VC2010、VC2012等运行库,包含32及64位版本。这些运行库都是采用Microsoft Visual Studio 20XX编写的软件必须使用的公用DLL运行库。网上...

    3DM游戏运行库合集v2.8.rar

    运行库大全 Visual C++ 2005 运行库(x86) 8.0.61187........1 Visual C++ 2005 运行库(x64) 8.0.61186.........2 Visual C++ 2008 运行库(x86) 9.0.30729.7523.....3 Visual C++ 2008 运行库(x64) 9.0.30729.7523......

    C语言:标准与实现

    版本号 发布日期 主要的变化 0.9 07-01-04 初始版本 0.9a 07-06-04 1)整本书改用16开本进行排版,页数因此有所改变 2)所有命令的名字用不同的字体明确标识出来 ...3)补充关于动态库代码在运行期被载入程序映射进

    C++运行库大全

    C++运行库大全

    C++2008运行库

    提示缺少C++运行库的朋友们可以下载安装!

    C语言运行库

    《程序员的自我修养》C语言运行库实现代码,在Windows环境下编译通过。

    Visual C++6.0运行库参考手册

    第二部分为运行库参考,包括运行库例程分类、全局变量和标准类型、全局常量、调试版C运行库和运行类库字母顺序参考等五章。全书结构合理、文字简洁流畅且方便易查。它是从事Visual C++ 6.0 应用与开发的技术人员必备...

    Microsoft Visual C++运行库合集下载

    Microsoft Visual C++运行库合集由国外网友McRip制作,包含了VC2005、VC2008、VC2010、VC2012运行库,包含32及64位版本。这些运行库都是采用Microsoft Visual Studio 20XX编写的软件必须使用的公用DLL运行库。网上...

    vc2012_x64运行库

    vc2012_x64运行库VC2012运行库Visual C++ 2012 Redistributable Package 安装 Visual C++ 库的运行时组件,这些组件是在未安装 Visual Studio 2012 的计算机上运行使用 Visual Studio 2012 开发的应用程序所必需的。...

    微软常用运行库合集 2019.04.24下载地址

    这些运行库都是采用Microsoft Visual Studio 20XX编写的软件必须使用的公用DLL运行库,相当于程序的字典文件。 某些网上和论坛的部分精简软件没有附带这些公用DLL,所以安装这些运行库是系统安装后第一件要做的事情...

    antlr C语言运行时库

    antlr C语言运行时库; antlr C语言运行时库; antlr C语言运行时库

    三种环境下的openGL运行库文件

    最近在学习计算机图形学,所以我整理了用到的三种openGL运行库,包含了传统的C语言下的openGL运行库,和C#下(.NET 2.0)的openGL运行库SharpGL和C#(.NET 4.0)下的openGL运行库文件,还附带一本讲解超详细的NeHe中文版...

    微软常用运行库合集包 v2021.08.02 可自选更新.exe

    如果网友对电脑系统熟悉的都知道,我们平进使用软件都是Microsoft Visual Studio 编写的,所以这类软件的运行需要依赖微软Visual C++运行库,比如像 QQ、迅雷、Adobe 软件等等,如果没有安装VC++运行库或者安装的...

    microsoft微软常用运行库合集32+64位官方版

    本集合包含下列组件: Visual Basic Virtual Machine(5.1) Visual Basic Virtual Machine (6.0) ...这些运行库都是采用Microsoft Visual Studio 20XX编写的软件必须使用的公用DLL运行库,相当于程序的字典文件。

    微软常用运行库合集

    Windows微软常用运行库合集,这些运行库都是采用Microsoft Visual Studio 20XX编写的软件必须使用的公用DLL运行库,相当于程序的字典文件,某些网上和论坛的部分精简软件没有附带这些公用DLL,相信使用windows的朋友...

    VB6.0运行库

    VB6.0运行库 将ZIP解压后,放在系统盘(C:)下WINDOWS\SYSTEM32下即可。

    Visual C++微软常用运行库合集2022

    Microsoft Visual C++ ...此版Visual C++运行库组件合集(微软常用运行库合集)由国内封装爱好者@Dreamcast打包而成,整合Visual C ++组件安装包运行库所有版本,提供图形安装界面,可自选更新VC++版本。

Global site tag (gtag.js) - Google Analytics